深度解析 synchronized 锁升级机制
Java 中的 synchronized 锁升级是 JVM 优化同步性能的核心机制,其状态转换路径如下:
graph LR
A[无锁] --> B[偏向锁]
B --> C[轻量级锁]
C --> D[重量级锁]
1. 无锁 → 偏向锁
- 触发条件:
当线程首次访问同步块时,JVM 检测到无竞争环境(即未发生过锁争用)。 - 核心机制:
通过 CAS 操作将锁对象的 Mark Word 中的线程 ID 设置为当前线程 ID,并置标志位为101(偏向模式)。 - 优势:
后续该线程进入同步块时无需 CAS 操作,直接检查线程 ID 匹配即可。 - 数学描述:
设 $T_{id}$ 为线程 ID,$M$ 为 Mark Word,偏向锁建立过程可表示为:
$$ M_{\text{新}} = \text{CAS}(M_{\text{旧}}, \text{NULL}, T_{id}) \oplus \text{偏向模式位} $$
2. 偏向锁 → 轻量级锁
- 触发条件:
当第二个线程尝试获取锁时(发生轻度竞争),JVM 在全局安全点撤销偏向锁。 - 核心机制:
- 暂停持有偏向锁的线程
- 检查原线程状态:
- 若已退出同步块 → 直接转无锁状态
- 若仍在同步块中 → 升级为轻量级锁
- 将 Mark Word 复制到线程栈帧(Lock Record),并用 CAS 替换为指向 Lock Record 的指针(标志位
00)。
- 数学描述:
设 $P_{\text{LR}}$ 为 Lock Record 指针,升级过程为:
$$ M_{\text{新}} = \text{CAS}(M_{\text{旧}}, M_{\text{原值}}, P_{\text{LR}}) $$
3. 轻量级锁 → 重量级锁
- 触发条件:
满足以下任一条件:- 线程自旋超过阈值(默认 10 次)
- 等待线程数 > CPU 核心数
- 调用
wait()等阻塞方法
- 核心机制:
- JVM 创建重量级锁的监视器(Monitor)
- 将 Mark Word 替换为指向 Monitor 的指针(标志位
10) - 竞争线程进入阻塞队列,由操作系统调度
- 性能影响:
线程切换成本从纳秒级升至微秒级,满足关系:
$$ \text{切换开销}{\text{重量级}} \approx 100 \times \text{切换开销}{\text{轻量级}} $$
关键参数与优化
- 偏向锁延迟:
默认开启延迟(-XX:BiasedLockingStartupDelay=4000ms),避免启动阶段的竞争误判。 - 降级机制:
重量级锁不会主动降级,仅当对象无任何线程引用时回归无锁状态。 - 锁消除场景:
若 JIT 编译器通过逃逸分析确认无竞争,会直接跳过锁升级流程。
通过此机制,JVM 实现了从低竞争(偏向锁)到高竞争(重量级锁)的自适应优化,平衡了同步性能与资源开销。

被折叠的 条评论
为什么被折叠?



