并发编程(十):对象头 Mark Word 与 synchronized 锁升级机制
·
上一篇《并发编程(九)》我们已经知道:synchronized 锁的本质是对象锁,锁信息存在对象头里。但对象头到底长什么样?Mark Word 里存了什么?锁升级时,底层到底发生了什么变化?
这一篇,我们直接钻进 JVM 内存结构,讲一讲 对象头、Mark Word、锁状态、锁升级 。
一、Java 对象在内存里长啥样?
在 HotSpot 虚拟机里,一个对象在堆内存中分为三部分:
- 对象头(Object Header)
- 实例数据(Instance Data)
- 对齐填充(Padding)
我们关心的锁状态、哈希码、GC 年龄,全都存在 对象头 里。
二、对象头(Object Header)由什么组成?
HotSpot 的对象头分为两部分(数组多一个):
1. Mark Word(标记字)
- 存储:哈希码、GC 分代年龄、锁状态标志、持有锁的线程 ID 等。
- 这是 synchronized 锁升级的重要数据结构。
2. Klass Pointer(类型指针)
- 指向方法区中这个对象的类元数据。
- JVM 通过它知道这个对象属于哪个类。
3. 数组长度(只有数组对象才有)
- 占用 1 个字宽(Word)。
- 类型是 int,所以 Java 数组最大长度是
2^31 - 1。
三、字宽(Word)与对象头大小
- 32 位 JVM:1 Word = 4 字节
- 64 位 JVM:1 Word = 8 字节
对象头大小:
- 普通对象:2 个字宽
- Mark Word:1 Word
- Klass Pointer:1 Word
- 数组对象:3 个字宽
- 多 1 Word 存数组长度
四、Mark Word 核心字段(32 位 / 64 位结构一致)
Mark Word 是一个非固定结构,会随着锁状态变化而复用字段。
通用核心字段:
- hashCode:对象哈希码(未锁 / 偏向锁时存在)
- 分代年龄(Age)
- 占 4 bit
- 最大值 15(GC 最多 15 次晋升老年代)
- 锁状态标志位
- 占 2~3 bit
- 用来区分:无锁、偏向锁、轻量级锁、重量级锁、GC 标记
- 线程 ID / 指针
- 偏向锁:存偏向线程 ID
- 轻量级锁:指向栈中锁记录指针
- 重量级锁:指向 Monitor 对象
五、锁状态与标志位
| 锁状态 | 标志位 | 说明 |
|---|---|---|
| 无锁 | 01 | 对象刚创建,未被竞争 |
| 偏向锁 | 01 | 无多线程竞争,锁偏向第一个线程 |
| 轻量级锁 | 00 | 轻度竞争,CAS 自旋 |
| 重量级锁 | 10 | 激烈竞争,OS 互斥量,线程阻塞 |
| GC 标记 | 11 | 被 GC 标记,不是锁状态 |
关键点:
- 无锁 & 偏向锁:标志位都是 01靠另外一位(偏向位)区分。
六、synchronized 锁升级完整流程
锁升级路线:无锁 → 偏向锁 → 轻量级锁 → 重量级锁且只能升级,不能降级。
1. 无锁状态
标志位:01
Mark Word 存储:hashCode、分代年龄、偏向位 0
2. 偏向锁(Biased Lock)
标志位:01,偏向位 1
适用场景:只有一个线程反复进入同步块
原理:
- 第一个线程进入时,CAS 把线程 ID 写入 Mark Word
- 下次该线程再来,直接进,不需要 CAS
- 目的:减少无竞争场景下的 CAS 开销
偏向锁撤销:一旦有第二个线程竞争,偏向模式结束,升级为轻量级锁。
3. 轻量级锁(Lightweight Lock)
标志位:00
适用场景:线程交替执行同步块,轻度竞争
原理:
- 线程在自己栈帧中创建 Lock Record
- CAS 尝试将对象 Mark Word 指向这个 Lock Record
- 成功:获取锁
- 失败:自旋,不立即阻塞
升级条件:自旋次数 / 自旋线程达到阈值 → 膨胀为 重量级锁。
4. 重量级锁(Heavyweight Lock)
标志位:10
Mark Word 指向 Monitor 对象
原理:
- 依赖操作系统互斥量(Mutex)
- 未获取锁的线程进入 Entry Set 阻塞
- 锁释放时唤醒一个线程,再次竞争
特点:
- 线程阻塞、唤醒 → 涉及用户态 / 内核态切换
- 开销最大,只适合高竞争、长持有场景
七、锁升级的完整逻辑(一句话总结)
- 无锁:没人用
- 偏向锁:一个线程反复用
- 轻量级锁:线程交替用,轻度竞争
- 重量级锁:激烈竞争,大量线程阻塞
JVM 根据竞争激烈程度自动升级,目的是:在安全前提下,尽可能减少性能开销。
八、Mark Word 结构变化
不同锁状态下,Mark Word 存储内容完全不同:
- 无锁:hashCode + 年龄 + 01
- 偏向锁:线程 ID + epoch + 年龄 + 01
- 轻量级锁:指向栈中锁记录的指针 + 00
- 重量级锁:指向 Monitor 的指针 + 10
- GC 标记:GC 相关信息 + 11
这就是为什么说:Mark Word 是 synchronized 锁升级的底层载体。
更多推荐


所有评论(0)