闪电疯狂赛车
91.44M · 2026-03-23
在 Java 开发者的眼中,synchronized 曾经是“笨重”的代名词。早期版本的 synchronized 一上来就直接调用操作系统的底层同步机制,导致线程上下文切换频繁,效率极低。
但在 Java 6 之后,HotSpot 虚拟机为了优化性能,对 synchronized 引入了极其精妙的“锁升级”机制。今天,我们就通过深度分析对象头、CAS 竞争和 Monitor 机制,彻底讲透锁升级的原理。
早期的 synchronized 只有 重量级锁 一种形式。每当一个线程请求锁,都会触发:
这种操作极其耗时。但在实际业务中,科学家们发现:
锁升级的目的,就是为了根据实际的竞争激烈程度,逐步“按需加重”锁的开销。
要理解锁升级,必须先看懂 Java 对象头(Object Header)。每个 Java 对象在内存中都带有一个“头”,其中的 Mark Word 是控制锁状态的核心。
在 64 位 JVM 中,Mark Word 占 8 个字节(64 bit)。它是一个“变色龙”,在不同的锁状态下,位域的含义完全不同:
| 锁状态 | 25 bit | 31 bit | 1 bit | 4 bit | 1 bit (偏向位) | 2 bit (锁标志位) |
|---|---|---|---|---|---|---|
| 无锁 | 未使用 | hashCode | 0 | 分代年龄 | 0 | 01 |
| 偏向锁 | ThreadID (54bit) | Epoch (2bit) | 0 | 分代年龄 | 1 | 01 |
| 轻量级锁 | 指向栈中锁记录 (Lock Record) 的指针 | 00 | ||||
| 重量级锁 | 指向互斥量 (Monitor) 的指针 | 10 |
核心逻辑:如果锁总是被同一个线程获取,那么标记一下线程 ID 就行了,连 CAS 都不需要。
核心逻辑:当出现了多个线程交替访问,但没有激烈竞争时,使用 CAS 替换对象头。
核心逻辑:当自旋次数过多,或者多个线程同时激烈争夺时,锁变得极其沉重。
ObjectMonitor 对象。WaitSet 或 EntryList 等待区,被操作系统挂起,进入阻塞状态。通过 javap -c 观察代码,你会发现同步块是由配对的指令控制的。
public class SyncExample {
public void syncBlock() {
synchronized (this) {
// 业务逻辑
}
}
}
对应的字节码摘要:
0: aload_0
1: dup
2: astore_1
3: monitorenter // 代表锁的开始
...
15: monitorexit // 代表正常退出
...
21: monitorexit // 代表异常退出(确保锁一定释放)
在实际工作中,我们可以使用 JOL (Java Object Layout) 工具来实时观察 Mark Word 的位变化。
import org.openjdk.jol.info.ClassLayout;
/**
* 使用 JOL 观察对象头锁标志位
*/
public class JOLDemo {
public static void main(String[] args) {
Object obj = new Object();
// 1. 无锁状态
System.out.println("--- 无锁状态 ---");
System.out.println(ClassLayout.parseInstance(obj).toPrintable());
synchronized (obj) {
// 2. 这种情况下可能是偏向锁或轻量锁(取决于 JVM 启动参数)
System.out.println("--- 锁住状态 ---");
System.out.println(ClassLayout.parseInstance(obj).toPrintable());
}
}
}
注:由于 JVM 默认偏向锁有 4s 延迟,直接运行可能先看到轻量级锁。
反驳:在 HotSpot 虚拟机中,锁升级通常是 单向不可逆 的(偏向锁 -> 轻量级锁 -> 重量级锁)。虽然在偏向锁撤销后可能重新进入偏向状态,但轻量锁一旦升级为重量锁,通常不会再自动“降级”回去。
反驳:自旋(Spin)只是一种 手段,它发生在轻量级锁升级为重量级锁的过程中。轻量级锁本身是利用 CAS 替换指针,而当 CAS 失败时,才会开启自旋优化以期不挂起线程。
预估并发压力:
如果你的场景天生就是极高并发、大量争抢(如秒杀核心逻辑),synchronized 可能会迅速膨胀为重量级锁。此时可以考虑 ReentrantLock 提供的更丰富的 API。
JVM 调优建议:
-XX:BiasedLockingStartupDelay=0 来关闭延迟,或者彻底禁用偏向锁。synchronized 的设计哲学体现了 Java 性能优化的核心思想:平路加速,上坡减挡。在没有竞争时追求极致性能,在竞争激烈时保证结果正确。理解锁升级,是你通向 Java 并发架构师的必经之路。