synchronized 与 ReentrantLock 有什么区别?
未标记
考查重点:互斥能力与显式锁控制。两者可重入互斥,ReentrantLock 多中断/定时尝试/条件队列,需 finally 释放
本题目录
参考答案
核心回答
两者都能提供互斥、可重入及相应的内存可见性保证。synchronized 是语言级监视器机制,进入与退出同步范围由语言和 JVM 管理;ReentrantLock 是显式锁 API,提供可中断获取、限时或立即尝试、公平性配置以及多个条件队列等更细控制。
选型重点是需要哪些控制能力和代码是否容易正确维护,不能沿用“synchronized 一定性能差”的旧结论。
使用与能力上的区别
释放方式:synchronized 代码块或方法正常退出、抛异常退出时会释放相应监视器。ReentrantLock 成功获取后需要在 finally 中调用 unlock();获取失败时不能执行解锁。重入多少次通常就要匹配释放多少次。
等待控制:进入监视器的锁获取没有对应 tryLock 或可中断获取接口;ReentrantLock 支持立即尝试、带超时尝试和 lockInterruptibly(),适合需要截止时间或取消响应的流程。方法内部执行可中断操作是另一件事,不要与锁获取阶段混淆。
公平性:ReentrantLock 可配置公平模式,在竞争下偏向等待最久的线程,但不保证线程调度公平;无超时版本 tryLock() 也不遵循公平设置。公平模式可能降低吞吐,应基于实际等待和延迟要求选择。
条件等待:监视器使用 wait/notify/notifyAll 和关联的等待集;ReentrantLock 可通过多个 Condition 把“队列非空”“队列未满”等条件分开。等待前后都需要遵循持锁规则,并用循环复查条件,防止虚假唤醒或条件被其他线程改变。
实现层面如何回答
synchronized 的具体实现和优化由 JVM 决定。ReentrantLock 基于 AQS 等机制管理同步状态、等待与唤醒;同一线程重复获取时增加重入计数,释放到零才真正让出锁。说明原理时应注明源码版本,不能将某一 JDK 的节点字段或历史锁升级流程视为永久规范。
简单的临界区可以优先使用容易写对的同步方式;明确需要超时获取、可中断等待或多个条件时,ReentrantLock 更便于表达。两者都需要正确锁粒度、统一加锁顺序,避免持锁做慢远程调用。
常见追问
两者都能避免死锁吗? 不能。可中断和超时接口能帮助设计退出策略,但仍要避免循环等待;超时退出还要正确清理已取得的资源。
参考资料
- 国内:JavaGuide / Snailclimb:Java 并发常见问题(二):参考可重入、等待控制与条件通知的比较,组织正文中 synchronized 与 ReentrantLock 的选型维度。
- 国内:美团技术团队(JavaGuide 授权收录):从 ReentrantLock 的实现看 AQS 的原理及应用:借鉴同步状态与获取释放流程,解释正文中 ReentrantLock 的可重入计数及排队机制。
- 国内:JavaGuide / Snailclimb:AQS 详解:采用同步器的状态与队列模型,解释正文中显式锁如何支持阻塞、唤醒和获取策略。
- 国外:Oracle:ReentrantLock API, SE21:官方接口核对公平模式的边界和显式解锁要求,避免将公平性理解为线程调度保证。
- 国外:Oracle:JLS SE21 Chapter17:监视器规则说明 synchronized 如何获得、重入和释放锁,并提供比较的语言级依据。


