java synchronized锁升级由jvm自动管理,基于对象头mark word的位模式实现无锁→偏向锁→轻量级锁→重量级锁的单向演进,开发者需理解触发条件与状态标识而非手动控制。

Java原生的synchronized锁升级流程完全由JVM自动管理,开发者无法显式“使用”偏向锁或轻量级锁,但可以通过理解对象头(特别是Mark Word)的变化,观察、验证并合理引导锁的状态演进。关键不在于手动调用,而在于掌握其触发条件、状态标识和运行时行为。
对象头锁升级的核心载体是Mark Word
每个Java对象在堆中都有一个对象头,其中Mark Word(64位JVM为64 bit,32位为32 bit)动态存储锁状态、线程ID、GC年龄等信息。锁的四种状态(无锁→偏向锁→轻量级锁→重量级锁)全部通过Mark Word中固定比特位的组合来标识,JVM依据这些位值决定如何处理synchronized请求。
偏向锁:单线程场景下的零开销优化
- 触发时机:对象首次被某个线程进入
synchronized块,且此时无竞争 - Mark Word变化(64位JVM):
- 原始无锁态:低2位为
01,高位存hashCode或0,偏向位为0 - 升级后:偏向位设为
1,54位填入当前线程ID,低2位仍为01
- 原始无锁态:低2位为
- 行为特点:该线程后续重入无需CAS,仅比对线程ID即可;其他线程尝试获取会触发偏向撤销(需STW暂停,但极短暂)
轻量级锁:多线程交替但无激烈竞争时的自旋抢锁
- 触发时机:偏向锁被撤销(即第二个线程竞争),且未达到自旋阈值
- Mark Word变化:低2位变为
00,其余62位存指向当前线程栈帧中Lock Record的指针 - 行为特点:
- 线程在自己的栈上创建Lock Record,拷贝原Mark Word(Displaced Mark Word)
- 用CAS将对象头更新为指向该Lock Record的指针
- 若CAS失败(说明已被其他线程抢占),则自旋重试(默认最多10次,可由
-XX:PretenureSizeThreshold等参数影响)
重量级锁:自旋失败或竞争加剧后的系统级阻塞
- 触发时机:轻量级锁自旋超限、或多个线程同时争抢、或持有锁时间过长
- Mark Word变化:低2位变为
10,其余62位存指向堆中Monitor对象的指针 - 行为特点:线程挂起,进入操作系统内核态等待队列,发生用户态→内核态切换,开销显著上升
如何实际观察与验证锁状态?
- 使用JOL(Java Object Layout)工具打印对象头:
System.out.println(ClassLayout.parseInstance(lock).toPrintable());
配合
-XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0启动参数,确保偏向锁默认启用 - 控制竞争节奏辅助观察:
- 单线程反复
synchronized(lock)→ 可稳定维持偏向锁 - 两线程错峰执行(如Thread-1 sleep后再启动Thread-2)→ 易停留在轻量级锁
- 多线程高密度争抢(如for循环启10个线程同步操作)→ 快速膨胀至重量级锁
- 单线程反复
- 注意:调用
obj.hashCode()会使对象永久失去获得偏向锁的资格(因Mark Word需复用空间存hash,与线程ID冲突)
锁升级不可逆,且全程无代码干预点——它不是API,而是JVM基于Mark Word位模式与竞争实时决策的底层机制。真正有效的“使用”,是写出符合各锁适用场景的代码:避免无谓哈希计算、控制临界区粒度、减少锁持有时间,让JVM有空间保持在更轻量的状态。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











