synchronized锁升级不可逆,重量级锁形成后不会降级为轻量级或偏向锁。原因在于重量级锁已绑定操作系统互斥量,降级需同步唤醒线程、清空队列等,开销大且风险高;HotSpot源码无deflate逻辑,仅支持inflate单向升级。

是的,synchronized 锁升级流程在运行时完全不可逆——这不是 bug,而是 HotSpot JVM 的明确设计选择。
重量级锁一旦形成,就再不会退回轻量级或偏向锁
当锁膨胀到重量级状态(Mark Word 指向 ObjectMonitor),JVM 就不再尝试降级。原因很实在:
- 重量级锁已绑定操作系统互斥量,线程可能被挂起、栈帧不可达,JVM 无法安全重建轻量级锁所需的栈上 Lock Record
- 降级需同步唤醒所有阻塞线程、清空 Monitor 内部队列、重置 Owner 和 EntryList 等状态——开销远超收益,且极易引入竞态风险
- HotSpot 源码中只有 inflate(膨胀)逻辑,没有对应 deflate(收缩)实现;这不是遗漏,是刻意省略
所谓“降级”其实是误解,真正发生的只是偏向锁撤销
你可能看到过“锁在安全点被降级”的说法,但这仅适用于偏向锁:
- GC 或 JIT 编译触发安全点时,JVM 会批量撤销尚未升级的偏向锁,把对象头恢复为无锁状态(锁标志位 01)
- 这个操作不作用于重量级锁,也不产生轻量级锁,更不是运行时动态收缩,只是对“还没真正竞争”的锁做清理
- 一旦锁走到轻量级或重量级阶段,安全点期间也不会把它变回去
轻量级锁失败后也不会回退尝试偏向
自旋耗尽、CAS 失败后,JVM 直接调用 inflate 升为重量级锁,不会回头检查能否重新偏向:
立即学习“Java免费学习笔记(深入)”;
- 此时已有至少两个活跃线程争抢,违背了偏向锁“单线程长期持有”的前提
- 再尝试写入线程 ID 是徒劳的 CAS,成功率极低,纯属浪费 CPU 和内存屏障
- 源码中 ObjectSynchronizer::slow_enter 的路径是单向的:轻量失败 → 膨胀 → 重量级
不可逆的本质是性能与安全的平衡取舍
JVM 不追求“理论上可逆”,而是选择确定性更强、开销更可控的路径:
- 避免因反复升降带来的额外状态校验、内存屏障和分支判断
- 防止表面空闲实则隐含竞争(比如刚释放锁,另一个线程已在内核态排队)
- 让锁行为可预测:开发者能通过监控确认当前锁处于哪一阶,而不必担心它突然“缩水”又“反弹”


















