非公平锁吞吐量高30%–50%,因先CAS抢占再入队,省去每次加锁的队列检查并利用“热线程优势”;公平锁严格FIFO排队,需每次调用前检查前驱节点,导致延迟高、唤醒频繁、开销大。

核心差距在锁获取路径的“竞争前置性”和“队列管理开销”上。非公平锁吞吐量通常高30%–50%,但可能引发线程饥饿;公平锁保障FIFO顺序,代价是响应延迟更高、CPU唤醒更频繁。
非公平锁:先抢后排,减少等待
新线程尝试获取锁时,**不查队列、不守秩序,直接CAS抢占**。只有抢失败了,才进CLH等待队列尾部。这带来两个关键优势:
- 避免每次加锁都检查等待队列(省掉
hasQueuedPredecessors()调用) - 刚释放锁的线程,极大概率能立即再次抢到(称为“热线程优势”),减少上下文切换
- 多个线程并发争锁时,成功获取的线程数更多,单位时间完成的操作更多
公平锁:严格排队,顺序确定但慢
每次调用tryAcquire()前,**强制检查是否有前驱节点在队列中等待**:!hasQueuedPredecessors()为true才允许尝试CAS。这意味着:
- 即使锁刚被释放,新线程也必须排队,不能插队
- 队列中除头节点外,其余线程长期处于阻塞态,唤醒成本高
- 在高并发场景下,大量线程反复入队/出队,AQS内部链表操作和volatile读写开销明显上升
实测性能差异直观体现
在16核服务器执行100万次计数器累加(单锁保护):
| 锁类型 | 耗时(ms) | 吞吐量(ops/ms) |
|---|---|---|
| 公平锁 | 1250 | 800 |
| 非公平锁 | 850 | 1176 |
非公平锁快约32%,主要节省在锁释放后“空档期”的抢占机会——这个窗口期里,公平锁只能唤醒队首线程,而非公平锁允许任意线程瞬时介入。
底层机制差异一句话总结
非公平锁的lock()方法第一步就是compareAndSetState(0, 1);公平锁则多一步判断!hasQueuedPredecessors(),这个布尔检查背后是遍历AQS同步队列的head/tail指针与前驱节点状态,属于不可忽略的内存屏障开销。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











