1073 字
约 3 分钟
5
S05-B03 · synchronized 与锁升级
2024-12-31
2026-11-07

适用读者:背过"偏向锁→轻量级锁→重量级锁"但说不清细节的人。
前置:S05-B01。
实测环境:OpenJDK 21.0.12.1(2026-11-05)。
覆盖旧文:A-1120(371) A-938(75) A-1606(89) A-2637(114) + 1607(157) 939(76) 1028(105) 940(73) 930(81) = 1,141 点。
覆盖扩展:E-S05-004(监视器与 Mark Word)、E-S05-005(偏向锁已废弃)。
上一篇:S05-B02 · 线程状态机与创建方式
下一篇:S05-B04 · ThreadLocal。


1. 一句话结论

synchronized 的实现是"对象头里的 Mark Word + 监视器(monitor)"。所谓"锁升级",是 JVM 为了省下系统调用开销而做的三级优化——它优化的是"竞争程度",不是"锁的功能"。


2. 它锁的是什么(E-S05-004)

修饰位置 锁的对象
实例方法 当前实例(this)
静态方法 Class 对象
同步代码块 括号里的对象

关键认知:锁信息在对象头(Mark Word)里,不在方法上。所以"两个线程锁不同的对象"互不阻塞。

对象头 Mark Word(64 位 JVM):
  hashCode | 分代年龄 | 锁标志位 | 偏向线程 ID ...
              ↑ 锁状态就编码在这几个 bit 里

3. 三级"升级"

阶段 触发条件 代价 说明
偏向锁 只有一个线程反复进入 最低(CAS 一次记 ID) JDK 15 起默认禁用、后续版本移除(E-S05-005)
轻量级锁 有第二个线程竞争(短暂) 中(CAS 自旋) 自旋失败→膨胀
重量级锁 自旋失败/竞争激烈 高(内核互斥量,线程阻塞) 涉及用户态/内核态切换

实测佐证(B01):8 线程 × 20 万次 synchronized 递增 101 ms,比无锁版本(121 ms)还快——因为低竞争下走的是轻量级路径,并没有真的进内核。

"升级不可逆":一旦膨胀为重量级,不会退回轻量级(这是常见面试点,也是"为什么不要滥用 sync"的原因之一)。


4. 与 ReentrantLock 的对比

维度 synchronized ReentrantLock
释放 自动(异常也释放) 必须 finally 手动释放
可中断 ❌ ✅ lockInterruptibly
超时 ❌ ✅ tryLock(timeout)
公平性 非公平 可选公平
条件变量 wait/notify(单条件) 多 Condition
实现 JVM 层(monitor) Java 层(AQS,J01)

判据:需要超时/可中断/多条件 → ReentrantLock;否则用 synchronized(更简单、不会漏释放)。


5. 死锁:四个必要条件与本系列的看法

条件 破坏方式
互斥 尽量无锁(CAS/不可变)
占有并等待 一次性申请全部资源
不可剥夺 支持超时(tryLock)
循环等待 统一加锁顺序

排查手段:jstack <pid> 会直接输出 Found one Java-level deadlock(A02 详讲)。

注意区分:线程死锁(本系列)与数据库死锁(S11,A-2381/A-849 已移交)。


6. 五个误区

误区 真相
"锁加在方法上就锁住了方法" 锁的是实例/Class 对象
"锁升级会降级" 膨胀后不退回
"偏向锁一直有效" JDK 15+ 默认禁用、后续移除
"synchronized 一定比 ReentrantLock 慢" 低竞争下 sync 更快(JVM 优化)
"wait 与 sleep 一样" wait 释放锁,sleep 不释放

7. 自检

  1. synchronized 修饰实例方法/静态方法/代码块,各锁什么?
  2. 三级升级的触发条件分别是什么?
  3. 为什么说"低竞争下 synchronized 不慢"(用实测说明)?
  4. ReentrantLock 相比 synchronized 多出哪三个能力?
  5. 死锁的四个必要条件,哪个最容易在代码里被破坏?

8. 下一篇

S05-B04 · ThreadLocal:结构、场景与泄漏

锁讲完,下一篇讲"另一条路":不共享就不会有竞争——以及 ThreadLocal 为什么会导致内存泄漏。


本篇属于系列《S05 · Java 并发与 JVM》。旧文来源:A-1120/938/1606/2637/1607/939/1028/940/930;扩展点 E-S05-004/005。计时数据来自 OpenJDK 21 实测。

S05-B03 · synchronized 与锁升级
https://www.clxhxhhr.top/posts/5244/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。