synchronized 是 Java 中最基础的同步机制,从早期 JDK 版本的重量级锁 (完全依赖操作系统互斥量实现),到 JDK 1.6 后的锁优化 ,其核心目标是减少锁竞争带来的性能开销,让同步操作更轻量。下面是由浅入深讲解它的优化原理。
一、核心优化思路:从"重量级"到"分级锁"
JDK 1.6 对 synchronized 的优化核心是引入了分级锁机制 ------锁会根据竞争程度,从低开销的状态逐步升级到高开销状态(不可逆的升级过程,也叫"锁膨胀"),避免一上来就使用重量级锁。
先明确一个基础概念:
Java 对象在内存中包含 对象头 (Mark Word + 类型指针),synchronized 的锁状态就存储在对象头的 Mark Word 中(32 位 JVM 示例):
| 锁状态 | Mark Word 存储内容 |
|---|---|
| 无锁 | 对象哈希值 + 分代年龄 + 无锁标记 |
| 偏向锁 | 持有锁的线程 ID + 分代年龄 + 偏向锁标记 |
| 轻量级锁 | 锁记录(Lock Record)的指针 |
| 重量级锁 | 互斥量(Monitor)的指针 |
二、具体优化手段(按锁升级顺序)
1. 偏向锁:解决"无竞争"场景
适用场景 :只有一个线程反复获取同一把锁,完全无竞争。
核心原理:
- 首次获取锁时,JVM 会把对象头的
Mark Word中记录当前线程 ID,并标记为"偏向锁"状态; - 后续该线程再次获取锁时,只需对比对象头中的线程 ID:
- 如果匹配,直接获取锁(无需任何额外操作,开销极低);
- 如果不匹配(有其他线程竞争),则偏向锁升级为轻量级锁。
为什么高效:避免了每次获取锁都做 CAS 操作,几乎无开销。
2. 轻量级锁:解决"轻度竞争"场景
适用场景 :多个线程交替获取锁(无长时间阻塞),竞争不激烈。
核心原理:
- 线程获取锁时,JVM 会在该线程的栈帧中创建一个 Lock Record(锁记录) ,并将对象头的
Mark Word复制到 Lock Record 中; - 通过 CAS 操作 将对象头的
Mark Word替换为指向该 Lock Record 的指针:- CAS 成功:获取锁,对象头标记为"轻量级锁";
- CAS 失败:说明有其他线程竞争,此时会自旋几次(见下文"自旋锁"),若自旋成功则仍保持轻量级锁,失败则升级为重量级锁。
为什么高效:基于 CAS 操作(用户态操作),无需切换到内核态,开销远低于重量级锁。
3. 自旋锁 & 自适应自旋:减少内核态切换
这是轻量级锁升级为重量级锁前的"缓冲优化":
- 自旋锁 :当线程获取锁失败时,不直接阻塞(阻塞会切换到内核态,开销大),而是循环几次(自旋),尝试再次获取锁。因为多数情况下,锁会很快被释放,自旋能避免内核态切换。
- 自适应自旋:JVM 不再固定自旋次数,而是根据"前一次获取该锁的自旋次数""锁的拥有者状态"动态调整。比如某把锁自旋成功过,就增加自旋次数;反之则减少,甚至不自旋。
4. 重量级锁:解决"重度竞争"场景
当自旋失败(说明锁竞争激烈),轻量级锁会升级为重量级锁:
- 此时对象头的
Mark Word会指向一个 Monitor(监视器) 对象(由操作系统提供); - 未获取到锁的线程会被阻塞,进入 Monitor 的等待队列,直到锁被释放后由操作系统唤醒。
- 缺点:涉及用户态 ↔ 内核态切换,开销大;但优点是能处理高竞争场景。
三、补充优化:锁消除 & 锁粗化
除了分级锁,JVM 还会通过编译器优化减少不必要的锁操作:
1. 锁消除
JVM 检测到某些锁对象是"局部变量"(不会被多线程访问),会自动消除这些锁。比如:
java
public void test() {
// StringBuffer 是线程安全的(方法加了 synchronized),但此处是局部变量,无多线程访问
StringBuffer sb = new StringBuffer();
sb.append("a").append("b");
// JVM 会消除 sb.append() 中的 synchronized 锁
}
2. 锁粗化
JVM 会将多个连续的、对同一把锁的加锁/解锁操作合并为一次,减少锁操作次数。比如:
java
// 优化前:多次加锁/解锁
for (int i = 0; i < 1000; i++) {
synchronized (lock) {
// 少量操作
}
}
// JVM 优化后:一次加锁/解锁
synchronized (lock) {
for (int i = 0; i < 1000; i++) {
// 少量操作
}
}
四、可视化锁升级流程
单个线程首次加锁
其他线程竞争
自旋失败/竞争激烈
无锁状态
偏向锁
轻量级锁
重量级锁
锁消除/锁粗化:编译器层面优化
自适应自旋:轻量级锁升级前的缓冲
总结
synchronized的核心优化是分级锁机制:从偏向锁(无竞争)→ 轻量级锁(轻度竞争)→ 重量级锁(重度竞争),锁升级不可逆,目的是按需使用低开销的锁状态。- 辅助优化手段包括自旋锁(自适应) (减少内核态切换)、锁消除 (移除无意义锁)、锁粗化(合并锁操作)。
- 优化本质:尽可能在用户态完成锁操作,避免切换到内核态(重量级锁的核心开销),从而提升同步效率。