Skip to Content
面试题库Juc[面试题] ReentrantLock 和 synchronized 有什么区别?为什么它也能支持可重入?

[面试题] ReentrantLock 和 synchronized 有什么区别?为什么它也能支持可重入?

📖 版块 A:知识讲解版 (温故知新)

  • 共同点

    1. 都是 Java 中的互斥同步手段。
    2. 都支持可重入,即同一线程可以重复获取同一把锁而不被自己阻塞。
    3. 都能保证原子性、可见性和有序性。
  • 核心区别

    1. 实现层级不同

      • synchronized 是 JVM 层面的内置锁。
      • ReentrantLock 是 JDK 层面的显示锁,底层基于 AQS。
    2. 使用方式不同

      • synchronized 自动加锁、自动释放。
      • ReentrantLock 需要手动 lock() / unlock(),通常要配合 try/finally
    3. 功能特性不同

      • ReentrantLock 支持 可中断获取锁超时获取锁公平锁/非公平锁切换Condition 条件队列
      • synchronized 在这些扩展能力上较弱。
  • 可重入实现原理

    1. ReentrantLock 内部维护一个 AQS state 状态值。
    2. 第一次获取成功时,state 从 0 变为 1,并记录持有线程。
    3. 同一线程再次获取时,直接把 state 加 1。
    4. 释放锁时,state 递减,直到减为 0 才真正释放。
  • 适用建议

    • 逻辑简单、同步范围清晰:优先 synchronized
    • 需要更强控制能力:优先 ReentrantLock

🎤 版块 B:面试实战版 (高手逐字稿)

Q:ReentrantLock 和 synchronized 有什么区别?为什么它也能支持可重入?

💬 高手逐字稿

ReentrantLocksynchronized 本质上都是解决多线程互斥访问的问题,但它们属于两套不同层级的实现。

synchronized 是 JVM 原生支持的内置锁,语法层面更简洁,进入同步块自动加锁,退出时自动释放。ReentrantLock 则是 JUC 提供的显示锁,底层基于 AQS,需要我们显式去 lock()unlock()。这意味着它的可控性更强,但同时也更容易因为忘记释放锁而出问题,所以工程上一定要写在 finally 里。

如果从能力上看,ReentrantLock 的优势主要有四个:

第一,它支持公平锁和非公平锁选择;第二,它支持可中断获取锁,也就是线程在等锁时可以响应中断;第三,它支持超时获取锁,比如 tryLock(timeout);第四,它支持多个 Condition 条件队列,能把不同等待条件拆开管理。相比之下,synchronized 更适合简单同步,而复杂并发编排一般会落到 ReentrantLock

至于它为什么可重入,底层关键就在 AQS 的 state 字段。第一次加锁成功时,state 从 0 改成 1,同时记录当前持有锁的线程是谁。后面如果还是同一个线程再次加锁,AQS 不会阻塞自己,而是直接把 state 再加 1。释放时则对应减 1,只有减到 0 才会真正把锁让出去。所以可重入的本质,就是“记录持有者 + 记录重入次数”。

我在面试里一般还会补一句:现在已经不太建议把它们对立成“ReentrantLock 一定比 synchronized 高级”。Java 6 之后 synchronized 做了很多锁优化,性能差距早就不是核心矛盾了。真正该看的,是你需不需要中断、超时、公平性、多个条件队列这些语义能力。如果不需要,synchronized 更稳、更不容易写错。

最后更新于:
⏱️

登录后开始阅读

当前 MVP 版本只开放邮箱密码登录注册。完成登录后即可进入面试题内容。

还没有账号?先去注册