公平锁的hasQueuedPredecessors()方法通过判断同步队列是否为空(h==t)及队首后继是否为当前线程,决定当前线程是否需排队;返回true则必须入队,false才允许CAS抢锁,这是公平性保障的核心机制。

公平锁的 hasQueuedPredecessors 方法是 AQS 判断当前线程是否该被阻塞的关键逻辑,它通过检查同步队列中是否存在“排在当前线程前面”的等待节点,来确保先到的线程先获取锁。
核心判断逻辑:队首后继是否为当前线程
该方法不看整个队列,只聚焦两个关键点:
- 同步队列是否为空(
head == tail)→ 空队列说明无等待者,返回false - 队首节点的后继节点是否存在,且该后继节点是否代表当前请求锁的线程 → 若是,说明当前线程已在队首之后排队,无需让出;否则说明有更早的线程在等,当前线程必须排队
实际代码精简逻辑等价于:return h != t && (!h.next.isShared() || h.next.thread != Thread.currentThread())
其中 h 是 head,t 是 tail;注意 AQS 队列是带哨兵头节点的,真正的第一个等待者是 head.next。
为什么只看 head.next?
因为 AQS 的同步队列是 FIFO 队列,新节点总是在 tail 后入队,而 head 永远指向一个已获锁或刚释放锁的“虚节点”。真正需要比较的,只有紧挨着 head 的那个节点(即最老的等待者),它代表队列中优先级最高的等待线程。只要它不是当前线程,就说明有更早的请求未被服务,当前线程就得继续排队。
和非公平锁的本质区别
非公平锁在 tryAcquire 阶段会直接尝试 CAS 抢锁,即使队列不为空也不管;而公平锁每次 acquire 前都调用 hasQueuedPredecessors(),结果为 true 就跳过抢锁,直接入队。这个“多一次检查”就是公平性的代价和保障。
常见误区提醒
- 不是检查自己是否在队列里:当前线程此时还未入队,方法判断的是“此刻是否有别人比我更早排队”
- head 和 tail 相等 ≠ 队列无人等待:刚初始化或刚清空时 head==tail;但唤醒后若新线程快速抢锁成功,也可能暂时 head==tail,此时无竞争,无需排队
- 该方法不加锁、无竞态:只读 volatile 字段(head/tail/next),靠 AQS 内存屏障保证可见性,性能开销极小
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











