面试知识库
困难

偏向锁-轻量级锁-重量级锁#

一句话答案#

锁升级路径:无锁→偏向锁(Mark Word 记录线程 ID)→轻量级锁(CAS 竞争)→重量级锁(Monitor 阻塞),不可降级。

核心要点

锁升级过程:

无锁 → 偏向锁 → 轻量级锁 → 重量级锁
      (单线程)  (短时竞争)   (激烈竞争)
plaintext
锁状态适用场景实现方式开销
偏向锁只有一个线程访问Mark Word 记录线程 ID,后续无需 CAS几乎无
轻量级锁多线程交替执行CAS 替换 Mark Word 为栈中 Lock RecordCAS 开销
重量级锁多线程同时竞争Monitor(mutex),未获锁线程阻塞线程阻塞/唤醒

升级触发条件:

  • 偏向→轻量级:第二个线程尝试获取锁时
  • 轻量级→重量级:CAS 自旋超过阈值(默认10次/自适应)

关键细节:

  • JDK15 默认关闭偏向锁(-XX:-UseBiasedLocking
  • 锁只能升级不能降级(GC 时特殊情况除外)
  • 偏向锁撤销需要等安全点(STW)
面试回答(2分钟版)

synchronized 的锁有一个从低到高的升级过程:无锁、偏向锁、轻量级锁、重量级锁,只能升级不能降级。偏向锁适用于始终只有一个线程访问同步块的场景,JVM 在对象头的 Mark Word 中记录线程 ID,后续该线程再进入时直接比对 ID 即可,几乎没有同步开销。当第二个线程尝试获取锁时,偏向锁撤销升级为轻量级锁,此时线程通过 CAS 将 Mark Word 替换为指向栈中 Lock Record 的指针来竞争锁,没拿到的线程自旋等待。如果自旋超过阈值(默认 10 次或自适应调整)仍未获取锁,就膨胀为重量级锁,底层使用操作系统的 mutex,未获锁的线程直接阻塞挂起,需要内核态切换,开销最大。值得注意的是 JDK 15 默认关闭了偏向锁,因为偏向锁撤销需要等待安全点会触发 STW,在现代多线程应用中弊大于利。理解锁升级机制有助于在编码时合理控制锁的粒度和竞争程度。

追问与易错

追问方向:

  • “偏向锁撤销的代价?”→ 需要等待全局安全点(STW),暂停持有偏向锁的线程来撤销,在多线程竞争频繁时安全点开销显著
  • “JDK15 为什么关闭偏向锁?”→ 现代应用多线程竞争普遍,偏向锁撤销的 STW 开销大于收益;偏向锁维护代码复杂增加了 JVM 维护成本,收益不再明显
  • “Mark Word 在不同锁状态存什么?”→ 无锁存 hashcode+age+锁标志 01;偏向锁存线程 ID+epoch+age+标志 01;轻量级锁存指向栈中 Lock Record 的指针+标志 00;重量级锁存指向 Monitor 的指针+标志 10

易错点:

  • ❌ 锁能降级——正常情况只升不降
  • ❌ 偏向锁就是不加锁——有 CAS 设置线程 ID 的开销