Java synchronized轻量级锁深度剖析:自旋机制与锁膨胀全解析
Java synchronized轻量级锁深度剖析:自旋机制与锁膨胀全解析
|
🌺The Begin🌺点点关注,收藏不迷路🌺
|
📌 本文导读:本文将深入剖析Java中synchronized轻量级锁的自旋机制,从源码层面解析锁膨胀过程,帮助你彻底理解轻量级锁何时自旋、如何自旋以及何时升级为重量级锁。全文包含四大核心章节、3个彩色流程图、5个源码片段。预计阅读时间22分钟。
一、🔴 核心答案:轻量级锁会自旋
是的,Java的synchronized轻量级锁在面临竞争时会进行自旋。
轻量级锁在加锁过程中,如果CAS操作失败,意味着存在锁竞争,线程会先尝试自旋(忙循环等待)来获取锁,而不是立即挂起线程。自旋是轻量级锁向重量级锁膨胀前的最后一道防线,目的是避免线程进入阻塞状态所带来的用户态/内核态切换开销。
📌 一句话理解:轻量级锁通过CAS加锁;当CAS失败时,线程会自旋重试;自旋超过一定次数仍未成功,锁就膨胀为重量级锁。
二、🔵 流程图:轻量级锁加锁与自旋全过程
三、🟣 源码层面:自旋发生在哪里?
3.1 🟤 轻量级锁加锁入口
轻量级锁的加锁逻辑在ObjectSynchronizer::slow_enter方法中。当偏向锁加锁失败(快速加锁阶段失败)后,JVM会进入慢速加锁过程,即轻量级锁加锁。
// 🔴 轻量级锁加锁核心逻辑(源码示意)
void ObjectSynchronizer::slow_enter(Handle obj, BasicLock* lock, TRAPS) {
// 复制对象头Mark Word到线程栈的Lock Record
markOop mark = obj->mark();
// CAS操作:尝试将Mark Word指向Lock Record
if (mark->is_neutral()) {
lock->set_displaced_header(mark);
if (mark == obj()->cas_set_mark((markOop) lock, mark)) {
// ✅ CAS成功,获得轻量级锁
return;
}
}
// ❌ CAS失败,进入锁膨胀流程(自旋+升级)
// ...
}
3.2 🟠 自旋的实现:ObjectMonitor::enter()
当轻量级锁CAS失败后,JVM会调用ObjectSynchronizer::inflate()获取ObjectMonitor对象,然后执行ObjectMonitor::enter()进行自旋加锁。
// 🟡 ObjectMonitor::enter()中的自旋逻辑(源码示意)
void ObjectMonitor::enter(TRAPS) {
// 1. 检查是否为重入
if (TryLock(Self) > 0) {
return; // 重入成功
}
// 2. 自旋锁阶段
if (TrySpin(Self) > 0) {
return; // 自旋成功获取锁
}
// 3. 自旋失败,进入重量级锁的阻塞队列
// ... 线程挂起
}
3.3 🟡 两种自旋机制
根据OpenJDK源码和社区分析,自旋分为两种:
| 自旋类型 | 特点 | 说明 |
|---|---|---|
| 固定次数自旋 | 自旋次数固定(默认10次) | 通过-XX:PreBlockSpin可调整 |
| 自适应自旋(JDK 1.6+) | 根据上次自旋结果动态调整 | 上次成功→增加次数;失败→减少或跳过 |
关于自适应自旋的详细原理,可以参考OpenJDK社区的相关讨论:自适应自旋会根据前一次在同一个锁上的自旋结果动态调整,如果自旋成功,JVM会认为这次也很有希望,从而允许自旋更长时间;反之,则可能直接跳过自旋。
四、🟤 流程图:自旋在锁升级中的位置
五、🟢 为什么需要自旋?——性能考量
5.1 🟠 自旋的价值
线程的阻塞和唤醒需要CPU从用户态切换到内核态,开销极大。如果锁的持有时间很短,让等待线程原地自旋(循环检查锁是否释放)比直接挂起更高效。
5.2 🟡 自旋的代价
自旋会占用CPU资源,如果锁被长时间占用,自旋的线程只会白白消耗CPU而无实际产出。因此自旋次数需要有限度,超过阈值后就应升级为重量级锁。
六、🔴 避坑指南
| 序号 | 要点 | 说明 |
|---|---|---|
| ① | 自旋不是独立的锁状态 | 自旋是轻量级锁在竞争时的一种策略,而非独立的锁状态 |
| ② | 自适应自旋是默认开启的 | JDK 1.6+默认开启,无需手动配置 |
| ③ | 自旋次数可通过JVM参数调整 | -XX:PreBlockSpin=10可设置固定自旋次数 |
| ④ | 高竞争场景自旋反而降低性能 | 竞争激烈时,应升级为重量级锁避免CPU空转 |
七、🔵 总结
synchronized轻量级锁确实会进行自旋。自旋发生在轻量级锁CAS失败后、升级为重量级锁之前,是避免线程阻塞的最后尝试。
三句话总结:
- 轻量级锁:通过CAS加锁,无竞争时性能最优
- 自旋锁:CAS失败后,线程忙循环等待,避免立即阻塞
- 重量级锁:自旋超时或竞争加剧,线程挂起,依赖操作系统Mutex

|
🌺The End🌺点点关注,收藏不迷路🌺
|
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐

所有评论(0)