reentrantlock公平锁通过aqs的clh队列实现严格fifo:每次获取锁前调用hasqueuedpredecessors()检查队列中是否有更早等待者,有则排队;入队cas保证顺序,唤醒仅针对head.next,确保逻辑上先到先服务。

ReentrantLock 通过内部的 AQS(AbstractQueuedSynchronizer) 实现公平锁的严格 FIFO 队列,核心在于:公平模式下,每次尝试获取锁前,先检查同步队列中是否有等待更久的线程;若有,则当前线程必须排队,不能插队。
公平锁的关键机制:acquire() 中的 hasQueuedPredecessors()
公平锁的 lock() 方法最终调用 AQS 的 acquire()。与非公平锁不同,公平锁的 tryAcquire() 实现中会调用 hasQueuedPredecessors() 判断是否该让步:
- 该方法检查 AQS 同步队列中是否存在比当前线程更早等待的节点(即 head.next 是否存在且不是当前线程)
- 只要队列中有等待者(哪怕还没被 park),当前线程就放弃抢锁,直接进入队列尾部
- 这从源头上杜绝了“刚唤醒或刚调用 lock() 就抢到锁”的插队行为
CLH 队列保证插入和唤醒的顺序性
ReentrantLock 使用 AQS 维护的双向 CLH(Craig, Landin, and Hagersten)变体队列实现 FIFO:
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
- 新线程入队时,总是通过 CAS 原子地追加到队尾(tail 指针更新),天然保持插入顺序
- 释放锁时,只唤醒 head.next 对应的节点(即队首等待者),唤醒顺序与入队顺序完全一致
- 每个节点的 waitStatus、prev/next 指针由线程安全操作维护,避免重排序或丢失通知
park/unpark 与状态流转配合队列调度
线程在队列中并非一直忙等,而是进入阻塞态,依赖精确的 unpark 唤醒:
- 未获取锁的线程调用 LockSupport.park() 进入 WAITING 状态,CPU 资源释放
- 持有锁的线程 unlock() 时,AQS 找到 head.next 节点并调用 LockSupport.unpark() 唤醒它
- 被唤醒线程重新执行 tryAcquire(),此时它已是队首,且无更早等待者,可成功获取锁
注意:FIFO 是队列级的,不是绝对时间意义上的“毫秒级先后”
公平性保障的是逻辑上的排队顺序,而非纳秒级精确:
- 两个线程几乎同时调用 lock(),因 CPU 调度、CAS 竞争微小差异,可能一个先入队、一个后入队,但不会颠倒顺序
- 只要入队成功,位置就固定;后续唤醒严格按 next 指针链表顺序进行
- 不保证线程从 park 到执行 tryAcquire 的耗时完全相等,但获取锁的权利严格按队列位置授予
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










