admin管理员组文章数量:1444919
synchronized 的锁升级机制详解
synchronized 是 Java 中实现线程同步的核心机制,其锁状态会随着竞争激烈程度动态升级,以提高并发性能。从 无锁 到 重量级锁 的升级过程包括四个阶段,且 不可逆。以下是具体流程及原理:
1. 无锁状态
- 特点: 对象初始化时处于无锁状态,此时没有线程持有锁。Mark Word(对象头的一部分)中存储对象的哈希码、分代年龄等信息,锁标志位为
01
- 适用场景: 单线程环境或未发生竞争的情况。
2. 偏向锁
- 设计目的: 减少同一线程重复获取锁的开销(如单线程执行同步代码块)
- 实现原理:
- 首次获取锁时,JVM 将线程 ID 记录到 Mark Word 中,并将锁标志位设为
01
(偏向锁标识位为1
)。 - 后续同一线程访问时,无需 CAS 操作,直接检查线程 ID 即可快速获取锁
- 首次获取锁时,JVM 将线程 ID 记录到 Mark Word 中,并将锁标志位设为
- 升级条件: 当其他线程尝试竞争锁时,偏向锁撤销(需等待全局安全点),并升级为轻量级锁
3. 轻量级锁
- 设计目的: 减少多线程交替执行时的阻塞开销,避免直接升级到重量级锁
- 实现原理:
- 线程通过 CAS 操作将 Mark Word 替换为指向栈帧中锁记录的指针,锁标志位变为
00
。 - 若 CAS 失败(存在竞争),线程进入自旋等待(空转循环),尝试有限次数的重试(默认 10 次,JDK 1.7 后引入适应性自旋)
- 线程通过 CAS 操作将 Mark Word 替换为指向栈帧中锁记录的指针,锁标志位变为
- 升级条件:
- 自旋超过阈值仍无法获取锁。
- 竞争线程数超过 1(如三个线程同时竞争)
4. 重量级锁
- 设计目的: 应对高并发竞争场景,通过操作系统互斥量(Mutex)实现阻塞机制
- 实现原理:
- Mark Word 中存储指向 Monitor 对象(C++ 实现)的指针,锁标志位变为
10
。 - 未获取锁的线程进入阻塞队列,由操作系统调度唤醒
- Mark Word 中存储指向 Monitor 对象(C++ 实现)的指针,锁标志位变为
- 缺点: 涉及用户态到内核态的切换,性能开销较大
锁升级的关键特性
- 不可逆性: 锁只能从低级别(如偏向锁)升级到高级别(如重量级锁),无法降级。这是为了避免频繁状态切换的开销
- 动态适应性: JVM 根据线程竞争情况自动选择锁策略,例如:
- 低竞争:偏向锁或轻量级锁减少开销。
- 高竞争:重量级锁保证线程安全
锁升级的触发条件与流程
锁状态 | 触发条件 | Mark Word 变化 |
---|---|---|
无锁 | 对象初始化时 | 哈希码 + 分代年龄 + 锁标志位 01 |
偏向锁 | 首次线程访问同步块 | 线程 ID + 锁标志位 01(偏向标识位 1) |
轻量级锁 | 多线程交替竞争或偏向锁撤销 | 栈帧锁记录指针 + 锁标志位 00 |
重量级锁 | 自旋失败或竞争线程数过多 | Monitor 指针 + 锁标志位 10 |
锁升级的优缺点
优点 | 缺点 |
---|---|
减少无竞争场景下的同步开销 5 54 | 重量级锁的阻塞机制导致高延迟 11 72 |
自适应不同并发场景,平衡性能与安全性 11 | 锁升级不可逆,可能过度升级到重量级锁 54 |
实际应用建议
- 避免过度同步: 缩小同步代码块范围,减少锁竞争概率。
- 监控锁状态: 使用工具(如 JOL)查看对象头信息,分析锁升级过程
- 替代方案: 在高并发场景下,可结合
ReentrantLock
或StampedLock
提升灵活性
通过理解锁升级机制,开发者可以更好地优化多线程程序的性能,避免因锁竞争导致的性能瓶颈
代码语言:java复制import org.openjdk.jol.info.ClassLayout;
public class LockUpgradeExample {
public static void main(String[] args) throws InterruptedException {
// 创建一个对象
Object obj = new Object();
System.out.println("===== 初始状态(无锁) =====");
System.out.println(ClassLayout.parseInstance(obj).toPrintable());
// 偏向锁延迟(默认 4s),确保偏向锁生效
Thread.sleep(5000);
// 首次获取锁,触发偏向锁
synchronized (obj) {
System.out.println("===== 偏向锁状态 =====");
System.out.println(ClassLayout.parseInstance(obj).toPrintable());
}
// 创建多个线程竞争锁,触发轻量级锁
for (int i = 0; i < 2; i++) {
new Thread(() -> {
synchronized (obj) {
System.out.println("===== 轻量级锁状态 =====");
System.out.println(ClassLayout.parseInstance(obj).toPrintable());
}
}).start();
Thread.sleep(1000);
}
// 高竞争场景,触发重量级锁
for (int i = 0; i < 3; i++) {
new Thread(() -> {
synchronized (obj) {
System.out.println("===== 重量级锁状态 =====");
System.out.println(ClassLayout.parseInstance(obj).toPrintable());
}
}).start();
}
}
}
本文标签: synchronized 的锁升级机制详解
版权声明:本文标题:synchronized 的锁升级机制详解 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/biancheng/1748214385a2827382.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论