面试复盘:synchronized 锁与 ReentrantLock 锁的区别及 AQS 认知完善

面试复盘:synchronized 锁与 ReentrantLock 锁的区别及 AQS 认知完善

在最近的一次面试中,面试官问了我一个并发相关的问题:"synchronized 锁和 ReentrantLock 锁有什么区别?"当时我给出了基础的回答,但脑海中浮现了 AQS(AbstractQueuedSynchronizer)的概念。由于对 AQS 了解有限,我没敢深入延伸。现在通过复盘和查阅资料,我希望完善这块知识,同时建构一个结构化的表达话术,以便未来面试中更自信地回答类似问题。

一、面试时的回答与反思

1. 我的回答

当时我的回答是这样的:

"synchronized 是 Java 的关键字,属于内置锁,简单易用,由 JVM 管理锁的获取和释放。ReentrantLockjava.util.concurrent.locks 包下的类,属于显式的锁,需要手动加锁和释放锁,功能更灵活。比如,ReentrantLock 支持公平锁和非公平锁的选择,还能响应中断、设置等待时间。而 synchronized 不支持这些特性,使用起来更简单,但灵活性较低。"

2. 反思

  • 优点 :我提到了两者的基本区别,比如内置 vs 显式、简单 vs 灵活,也点出了 ReentrantLock 的几个特性(公平性、中断、超时)。
  • 不足
    1. 回答比较表面,没能深入到实现原理,比如锁的底层机制。
    2. 想到 ReentrantLock 基于 AQS,但因不熟悉没敢展开,导致回答深度不够。
    3. 表达不够结构化,显得零散,没有清晰的逻辑框架。

3. 改进目标

通过复盘,我希望:

  • 补充 AQS 的知识,完善对 ReentrantLock 底层实现的理解。
  • 设计一个结构化的表达话术,逻辑清晰、层次分明。

二、synchronized 与 ReentrantLock 的区别(完善版)

经过查阅资料,我将两者的区别总结为以下几个维度,并融入 AQS 的理解:

1. 使用方式

  • synchronized

    • 关键字,内置于 JVM,直接修饰代码块或方法。

    • 加锁和释放由 JVM 自动管理,无需手动操作。

    • 示例:

      java 复制代码
      synchronized (obj) {
          // 同步代码块
      }
  • ReentrantLock

    • 显示锁类,需要手动调用 lock()unlock()

    • 释放锁必须放在 finally 块中,避免异常导致锁未释放。

    • 示例:

      java 复制代码
      ReentrantLock lock = new ReentrantLock();
      lock.lock();
      try {
          // 同步代码块
      } finally {
          lock.unlock();
      }

2. 功能特性

  • synchronized
    • 只支持非公平锁(先到先得)。
    • 不支持中断或超时等待。
    • 简单直接,适合基本同步场景。
  • ReentrantLock
    • 可选择公平锁(new ReentrantLock(true))或非公平锁。
    • 支持中断(lockInterruptibly())、超时(tryLock(long, TimeUnit))。
    • 提供条件变量(Condition),支持更复杂的同步逻辑。

3. 性能

  • synchronized
    • JDK 1.6 后优化显著,引入偏向锁、轻量级锁、重量级锁,性能接近 ReentrantLock
    • 但在高竞争场景下,仍依赖操作系统内核态的互斥锁(Mutex),开销较大。
  • ReentrantLock
    • 基于 AQS 实现,通过 CAS(Compare-And-Swap)和自旋锁在用户态完成大部分操作,减少内核态切换。
    • 在高并发场景下,性能可能略优于 synchronized

4. 底层实现

  • synchronized
    • 由 JVM 实现,依赖对象头中的 Monitor(监视器锁)。
    • 通过 monitorentermonitorexit 字节码指令控制。
  • ReentrantLock
    • 基于 AQS 框架,内部维护一个 volatile 状态变量(state)和等待队列。
    • 加锁通过 CAS 修改 state,失败则进入 AQS 队列等待。

5. 可重入性

  • 两者都支持可重入性,即同一线程可多次获取同一把锁,不会自我阻塞。

三、AQS 的简单认知

ReentrantLock 的底层依赖 AQS(AbstractQueuedSynchronizer),这是 Java 并发包的核心框架。以下是我通过查阅资料整理的 AQS 基础:

  • 核心思想
    • AQS 维护一个 volatile int state(表示锁状态)和一个双向链表队列(存放等待线程)。
    • state = 0 表示锁未被占用,state > 0 表示已加锁(支持重入,值递增)。
  • 加锁过程
    • 通过 CAS 尝试将 state 从 0 改为 1,成功则获取锁。
    • 失败则将线程加入等待队列,进入阻塞状态。
  • 释放锁
    • state 减 1,若减到 0,则唤醒队列中的下一个线程。
  • 与 ReentrantLock 的关系
    • ReentrantLock 通过继承 AQS 的 Sync 类实现锁逻辑。
    • 公平锁按队列顺序唤醒,非公平锁允许插队。

由于时间有限,我目前对 AQS 的理解停留在概览层面,后续需深入学习其源码(如 tryAcquiretryRelease 方法)。

四、结构化的表达话术设计

基于以上分析,我设计了以下面试表达话术,力求逻辑清晰、内容全面:

"面试官您好,关于 synchronizedReentrantLock 的区别,我可以从以下几个方面来回答:
第一,使用方式synchronized 是 JVM 内置的关键字,自动加锁和释放,用法简单;而 ReentrantLock 是 JUC 包中的类,需要手动调用 lock()unlock(),更灵活但要求开发者注意释放锁。
第二,功能特性synchronized 只支持非公平锁,且不支持中断或超时;ReentrantLock 则提供公平/非公平锁选项,还支持中断、超时等待,甚至可以用 Condition 实现复杂同步。
第三,性能表现 :早期 synchronized 性能较差,但 JDK 1.6 后通过偏向锁和轻量级锁优化,已接近 ReentrantLock。不过在高竞争场景下,ReentrantLock 因基于 AQS 和 CAS,减少了内核态切换,可能更有优势。
第四,底层实现synchronized 依赖 JVM 的 Monitor,由对象头控制;ReentrantLock 基于 AQS,通过 state 变量和等待队列管理锁状态。

如果要延伸,ReentrantLock 的 AQS 是一个通用同步框架,核心是维护一个状态值和线程队列,通过 CAS 实现高效加锁。我对 AQS 了解还不深入,但知道它是许多 JUC 工具(如 CountDownLatch)的基础,值得进一步学习。"

五、总结与计划

这次面试暴露了我对 AQS 的知识盲点,虽然基础回答没出错,但缺乏深度让我错失了展示能力的机会。通过复盘,我不仅完善了两者的区别,还初步理解了 AQS 的作用。未来计划:

  1. 阅读 ReentrantLock 和 AQS 的源码,掌握其实现细节。
  2. 练习结构化表达,提升回答的逻辑性和流畅性。
相关推荐
huan9922 分钟前
Obsidian 插件篇 - 插件汇总简介
后端
周Echo周24 分钟前
5、vim编辑和shell编程【超详细】
java·linux·c++·后端·编辑器·vim
AronTing29 分钟前
03-深入解析 Spring AOP 原理及源码
后端
逻辑重构鬼才31 分钟前
AES+RSA实现前后端加密通信:全方位安全解决方案
后端
卤蛋七号38 分钟前
JavaSE高级(一)
后端
Java中文社群1 小时前
SpringAI用嵌入模型操作向量数据库!
后端·aigc·openai
暴力袋鼠哥1 小时前
基于Flask的跨境电商头程预警分析系统
后端·python·flask
一只爱撸猫的程序猿2 小时前
防止外部API服务不可用拖垮系统的解决方案
spring boot·后端·程序员
白露与泡影2 小时前
SpringBoot 最大连接数及最大并发数是多少?
spring boot·后端·firefox
radient2 小时前
线上死锁问题排查思路
后端