非公平锁吞吐量大的本质是两次无条件cas抢占:线程到达时直接尝试获取锁,不查队列、不等顺序,成功则避免唤醒开销;失败才入队,从而减少上下文切换和cpu唤醒成本。

非公平锁的“插队”本质是两次无条件 CAS 尝试
非公平锁的 tryAcquire 并不真正“插队”,而是在线程刚到达时,**不查队列、不等顺序,直接抢一次锁**。这个动作发生在两个关键位置:
- 第一次在 lock() 方法入口:调用
compareAndSetState(0, 1),只要此时 state == 0(锁空闲),就立即成功,设置 owner 线程并返回 true; - 第二次在 acquire 流程中的 tryAcquire:即使已有线程在等待队列中,新线程仍会再试一次 CAS —— 这就是“二次抢占”的核心。
两次尝试之间没有状态检查或排队约束,完全跳过公平性校验(比如是否队首、是否前面有等待者)。只要锁恰好被释放、state 回到 0,新来的线程就可能比队首线程更快拿到锁。
为什么这能提升吞吐量?关键在减少上下文切换和唤醒开销
公平锁要求每次 unlock 后必须唤醒队首线程,而该线程被唤醒后还需重新调度、进入用户态、再执行 tryAcquire —— 整个过程涉及内核态切换、CPU 缓存失效、TLB 刷新等开销。非公平锁通过“插队”绕过了这个链条:
- 刚释放锁的瞬间,若恰有新线程正执行第一次 CAS,它可能在原线程退出临界区后 几纳秒内 就完成加锁,无需 park/unpark;
- 避免了对等待队列中线程的无谓唤醒(例如队首线程还没来得及运行,锁又被新线程抢走);
- 在高竞争场景下,多个线程反复争抢同一把锁时,CAS 失败成本远低于线程阻塞/唤醒成本。
“插队”不是无限制的:重入与失败后仍进队列
非公平 ≠ 不守规矩。它的“抢占”有明确边界:
- 如果锁已被占用(state > 0),且当前线程不是持有者,它不会无限重试,而是走标准流程:addWaiter → acquireQueued → park;
- 如果当前线程已持有该锁(可重入),则直接增加 state,不涉及任何抢占逻辑;
- 一旦进入等待队列,后续行为就和公平锁一致:按 FIFO 顺序被 unparkSuccessor 唤醒,不再允许二次插队。
也就是说,“插队”只发生在**锁空闲的瞬时窗口期**,且仅限于刚到达的新线程。它不破坏队列内部顺序,只是在队列外多给了一次机会。
实际影响:吞吐优先,但需警惕长尾延迟
基准测试表明,在多数并发场景下,非公平锁吞吐量比公平锁高 10%–30%。但代价是:个别线程可能连续多次抢占失败,被迫长时间等待 —— 特别是在锁持有时间短、竞争剧烈时,容易出现“饥饿感”。不过 JDK 默认采用非公平模式,正是因为大多数业务更看重平均响应和整体吞吐,而非单个请求的最坏延迟。










