synchronized锁升级是JVM根据竞争情况自动触发的单向过程:从偏向锁(无竞争时零开销)、到轻量级锁(少量线程交替竞争,CAS+自旋)、再到重量级锁(高竞争,OS级阻塞),全程依赖Mark Word状态位,不可逆。

synchronized 的锁升级不是代码控制的流程,而是 JVM 在运行时根据实际竞争情况自动触发的状态迁移。整个过程围绕对象头里的 Mark Word 展开,从偏向锁开始,逐步升级到重量级锁,且不可逆。
偏向锁:单线程场景的零开销优化
对象刚创建时处于无锁状态(Mark Word 锁标志位为 01,偏向标志位为 0)。当第一个线程进入 synchronized 块时,JVM 尝试将锁设为偏向状态:
- 通过一次 CAS 操作,把当前线程 ID 写入 Mark Word,并将偏向标志位设为 1,锁标志位仍为 01
- 后续该线程再次进入同一同步块,只需比对 Mark Word 中的线程 ID,匹配即直接执行,不消耗任何同步指令
- 适用于 getter/setter、单例初始化等几乎无竞争的场景
注意:JDK 15 起默认禁用偏向锁,可通过 -XX:+UseBiasedLocking 显式开启;若已禁用,则跳过此阶段,直接走轻量级锁路径。
轻量级锁:应对少量线程交替竞争
当另一个线程尝试获取已被偏向的锁时,JVM 撤销偏向状态(需到达安全点),并升级为轻量级锁:
立即学习“Java免费学习笔记(深入)”;
- 当前线程在自己的栈帧中创建一个 Lock Record,记录锁对象引用
- 用 CAS 将 Mark Word 替换为指向该 Lock Record 的指针,锁标志位变为 00
- 若 CAS 成功,获得锁;失败则说明存在竞争,进入自旋等待(默认最多 10 次)
- 自旋期间线程停留在用户态,避免操作系统线程挂起/唤醒开销
轻量级锁本质是“乐观锁”,适合线程交替执行、每次持有时间短的场景,比如简单计数器或短临界区。
重量级锁:高竞争下的最终保障
一旦轻量级锁自旋失败,或已有线程在等待队列中,JVM 就会将锁膨胀为重量级锁:
- Mark Word 被替换为指向堆中 Monitor 对象的指针,锁标志位变为 10
- Monitor 包含 Owner、EntryList 和 WaitSet 等字段,底层依赖操作系统互斥量(如 pthread_mutex)
- 未抢到锁的线程被阻塞,进入 OS 级等待队列,由内核调度唤醒
- 此时所有后续同步操作都走重量级路径,不再尝试降级或回退
可通过 jstack 查看线程状态为 BLOCKED,对应持有 Monitor 的线程即为锁拥有者。
关键细节与常见误区
锁升级是单向的,没有“降级”机制;升级决策完全由 JVM 运行时动态判断,开发者无法干预。Mark Word 是唯一状态载体,判断锁类型要同时看最后两位(锁标志位)和倒数第三位(偏向标志位):
- 01 + 偏向位=0 → 无锁
- 01 + 偏向位=1 → 偏向锁
- 00 → 轻量级锁
- 10 → 重量级锁
真正影响性能的不是“用了 synchronized”,而是是否频繁触发重量级锁——这往往意味着临界区过长、锁粒度过粗或竞争过于集中。


















