synchronized是非公平锁,因其释放锁后不按fifo顺序唤醒等待线程,而是允许新线程直接竞争锁,导致先到者未必先得,仅以cas抢占成败决定归属。

synchronized 的非公平性,核心在于“**不排队、先到先抢,抢到算数”**——它不维护线程申请锁的先后顺序,也不保证等待最久的线程一定优先获得锁。
为什么说它是“非公平”的?
当一个线程释放锁后,JVM 的 Monitor 并不会按 FIFO(先进先出)顺序唤醒等待队列(EntryList)中的第一个线程;而是直接让所有竞争线程(包括刚到达的新线程 + 队列里等了很久的老线程)一起用 CAS 等机制争抢锁所有权。这就意味着:
- 刚来的新线程可能比队列里等了几十毫秒的旧线程更快拿到锁;
- 没有“插队禁止令”,只有“谁快谁得”;
- Monitor 不记录“谁先来的”,只看“谁此刻能成功设置 Owner 字段”。
底层怎么实现“抢占”?
关键在 JVM 对 monitor 的实现逻辑中:释放锁时,并不强制唤醒 EntryList 中的头节点,而是允许新请求锁的线程直接尝试获取(barging)。具体表现为:
- 线程 A 释放锁 → Owner 清空;
- 此时线程 B(已在 EntryList 中等待)还没被唤醒,线程 C(刚发起请求)就立刻执行 lock 操作;
- C 直接用 CAS 尝试将 Owner 设为自己 —— 若成功,就跳过排队,直接持锁执行;
- 只有当 C 失败(Owner 已被别人抢走),它才会老老实实进 EntryList 排队。
和 ReentrantLock 公平锁对比更清楚
ReentrantLock(true) 的公平模式会严格检查:当前有没有线程在等待队列中?如果有,新线程必须排队,不能 barging。而 synchronized 压根没这层检查逻辑,它的设计哲学是:减少上下文切换和唤醒开销,以吞吐量优先。
这也解释了为什么高并发下可能出现“饥饿”——某个线程反复抢不过别人,一直卡在 EntryList 里出不来。
注意:非公平 ≠ 随机或恶意调度
这里的“非公平”是技术定义,不是系统故意打压某线程。它只是省去了排队校验步骤,把资源分配权交给竞争瞬间的执行效率和 CPU 调度。对大多数业务场景来说,这种设计反而更高效;只有在需要确定性响应时间(比如实时任务、金融结算)时,才需考虑用 ReentrantLock(true) 替代。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











