java中synchronized锁升级的核心载体是对象头的mark word,32位jvm中其为32位,64位jvm默认指针压缩后为64位但class pointer压缩为32位,从而扩展线程id等锁字段容量;锁状态均由末2位标识(01/00/10/11),结合biased位区分无锁与偏向锁,升级流程一致但触发边界和性能表现因位宽差异而不同。

Java中synchronized锁升级的核心载体是对象头里的Mark Word,而32位与64位JVM在对象布局、尤其是Mark Word的位宽和字段分配上存在本质差异——这直接决定了锁状态编码方式、可存储信息量以及锁升级的触发边界。
Mark Word总长度与字段对齐不同
32位JVM下Mark Word固定为32位;64位JVM默认开启指针压缩(-XX:+UseCompressedOops)后,Mark Word仍为64位,但其中Class Pointer压缩为32位,腾出空间给锁相关字段。未压缩时Class Pointer占64位,严重挤压Mark Word可用位数,实际生产环境几乎不启用。
- 32位JVM:Mark Word = 32 bit → 锁标志位(2 bit)、偏向锁标志(1 bit)、分代年龄(4 bit)、hashCode(25 bit)等紧凑排布
- 64位JVM(压缩指针):Mark Word = 64 bit → 可用有效位更多,例如偏向线程ID从23位扩展至54位,epoch保留2位,分代年龄仍为4位
偏向锁与轻量级锁的存储能力差异
偏向锁依赖Mark Word前段存储线程ID和epoch。32位环境下线程ID仅23位,理论上最多支持约838万不同线程标识;64位压缩模式下提升至54位,足以覆盖超大规模并发场景,降低因ID冲突导致的偏向撤销频率。
- 轻量级锁在32位JVM中用30位存栈中Lock Record地址;64位JVM则用62位存指针,兼容更大堆内存下的栈地址寻址
- 重量级锁同理:32位存30位ObjectMonitor指针,64位存62位指针,确保Monitor对象可位于任意堆地址空间
锁标志位逻辑一致,但上下文判断更复杂
无论32位还是64位,锁状态均由最后2位(lock bits)决定:01=无锁/偏向锁、00=轻量级锁、10=重量级锁、11=GC标记。关键区别在于:当lock bits为01时,需结合倒数第3位(biased lock bit)进一步区分无锁与偏向锁——该位在32位结构中位于bit 2(从0开始),在64位压缩结构中位于bit 4,位置偏移但语义完全相同。
- 32位Mark Word布局示例(无锁):[hashCode:25] [age:4] [biased:1] [lock:2]
- 64位Mark Word布局示例(偏向锁):[thread ID:54] [epoch:2] [age:4] [biased:1] [lock:2] [unused:1]
实际影响:升级阈值与调试表现不同
锁升级流程本身(无锁→偏向锁→轻量级锁→重量级锁)在两种JVM上逻辑一致,但触发条件受底层结构制约。例如:
- 偏向锁撤销开销在32位JVM中更高——因线程ID位数少,多线程竞争时更易发生hash冲突,迫使JVM提前撤回偏向
- 64位JVM在高并发下更倾向维持轻量级锁自旋,因Lock Record指针寻址范围大,栈空间管理更稳定
- 使用jhsdb或JOL工具观察对象头时,32位输出显示32进制或8字节hex,64位压缩模式显示为16字节hex但后半部分含填充位,需注意解析起始偏移
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











