reentrantlock默认采用非公平锁,核心原因是提升吞吐量并降低线程状态切换开销:非公平锁直接cas抢占空闲锁,成功则全程用户态、免唤醒;失败才入队,省去队列检查与内核态切换,而公平锁需每次校验队首且强制排队,导致更多阻塞、唤醒及延迟。

ReentrantLock 默认采用非公平锁,核心原因在于提升整体吞吐量,同时降低线程状态切换带来的系统开销。
非公平锁如何减少唤醒开销
线程在尝试获取锁时,不排队、不等待,而是直接用 CAS 操作抢占 state=0 的空闲状态。若成功,全程停留在用户态,无需挂起或唤醒;若失败,才进入 AQS 队列等待。这意味着:
- 没有“先检查队列是否为空”这一步判断,省去一次 volatile 读和条件分支
- 避免了大量线程反复从阻塞态被唤醒又发现锁仍被占用的无效调度
- CPU 不必频繁执行内核态切换(用户态 ↔ 内核态),而这种切换本身耗时显著
公平锁为何吞吐量更低
公平锁要求每个线程严格按入队顺序获取锁。实现上,它在 tryAcquire 中强制加入 !hasQueuedPredecessors() 判断——即只有当前队列为空或自己是队首时,才允许尝试获取锁。这带来明显代价:
- 每次 lock() 调用都必须检查同步队列头节点,增加 volatile 读与链表遍历开销
- 即使锁刚释放,新线程也不能立即抢入,必须等队首线程被唤醒、调度、执行、再释放,中间存在可观延迟
- 队列中多数线程长期处于阻塞态,依赖 unpark 操作唤醒,而 JVM 唤醒调度本身有成本
性能差异的实际体现
在高并发争抢场景下,非公平锁的单位时间锁获取成功率(吞吐率)通常比公平锁高出数倍。例如《Java 并发编程实战》中的基准测试显示,在典型多核服务器上,非公平 ReentrantLock 的吞吐量可达公平锁的 3~5 倍。这种优势并非来自“插队”的投机性,而是源于更少的状态跃迁、更紧凑的临界路径和更友好的 CPU 缓存行为。
公平性不是默认选项,但可显式启用
如果你确实需要避免线程饥饿、保障响应时间可预测(如定时任务调度、金融交易类系统),可以通过构造函数传入 true 启用公平模式:
new ReentrantLock(true);但要注意:开启公平性会以可测量的吞吐下降为代价,且不能完全消除饥饿(极端低优先级线程仍可能被持续压制),因此应基于真实压测结果做决策,而非直觉假设。










