考察点
JDK 6 对 synchronized 做了大优化之后,「synchronized 性能差」是过时的认知,面试官想确认你的知识跟上了版本。核心考点是锁升级的四级状态及每级解决的竞争程度,对象头 Mark Word 的布局是回答的骨架。追问常往「偏向锁为什么 JDK 15 被废弃」「锁能不能降级」「和 ReentrantLock 怎么选」走。
参考答案
前置知识:对象头
Java 对象在堆里的布局是对象头、实例数据、对齐填充。对象头里的 Mark Word 是锁状态的载体:32 位 JVM 下 32 bit,64 位下 64 bit,内容随锁状态变化而复用——无锁时存 hashCode、分代年龄;加锁后改成存锁记录指针或重量级锁指针,最低几位是锁标志位(01 无锁/偏向、00 轻量、10 重量)。理解「Mark Word 是个状态机」是理解锁升级的前提。synchronized 的锁对象就是这个对象头,普通方法锁 this,静态方法锁 Class 对象,代码块锁括号里的对象。
四级升级路径
锁只能升级不能降级(严格说 GC 时偏向锁会退,但常规语义是单向升级),设计的出发点是:锁开销应该和竞争程度匹配,低竞争场景不该付高代价。
无锁:对象刚创建,没有线程竞争。
偏向锁:假设锁总由同一个线程获得。第一次加锁时,用 CAS 把线程 ID 写进 Mark Word,之后该线程进出同步块没有任何 CAS 操作,只做简单检查,开销接近零。一旦出现第二个线程尝试获取锁(哪怕不真正竞争),偏向锁就要撤销——等全局安全点,检查持有线程是否还在同步块里,活着就升级为轻量级锁。撤销本身有 STW 成本,所以已知存在多线程交替竞争的场景,偏向锁是负优化,这也是它从 JDK 15 起默认禁用、JDK 18 彻底移除的原因之一。现代应用启动时就有大量同步类加载,偏向锁撤销开销超过收益。
轻量级锁:适用于线程交替进入、无真正并发冲突的场景。线程在进入同步块前在当前栈帧里开辟「锁记录」,用 CAS 把对象头的 Mark Word 替换成指向锁记录的指针,成功则获得锁;失败说明有竞争,先自旋(适应性自旋,JVM 根据历史成功率动态决定自旋次数),自旋期间不放弃 CPU——赌的就是持锁线程很快释放。自旋超过阈值还没拿到,升级为重量级锁。整个轻量级阶段没有操作系统介入,全是用户态的 CAS。
重量级锁:依赖操作系统的 Mutex Lock,拿不到锁的线程进入阻塞队列,发生用户态/内核态切换和上下文切换,开销最大,但有真正的并发竞争时这是唯一能保证正确性的方式。JDK 6 之后的重量级锁在等待队列管理上也做了优化,但本质上阻塞唤醒的成本绕不开。
其他配套优化
- 锁消除:JIT 逃逸分析发现锁对象不可能被其他线程访问(比如方法内部的局部 StringBuffer),直接把锁去掉。
- 锁粗化:同一个对象反复加解锁(循环里 append),JIT 把锁范围扩大到整个循环外,减少反复加锁开销。
- 锁降级:HotSpot 源码注释里有,但常规面试语境下「synchronized 只升不降」是对的回答,别在这上面纠缠。
和 ReentrantLock 的对比与选型
功能上 ReentrantLock 更强:可中断锁、超时获取(tryLock 带超时,是防死锁的利器)、公平锁可选、多 Condition 精确唤醒。性能上 JDK 6 之后两者差距已经不大,低竞争 synchronized 甚至更优。工程选型原则:能用 synchronized 就用它——JVM 原生支持、异常时自动释放不会泄漏、JIT 能做锁消除等优化;只有需要 ReentrantLock 独有功能时才用它,而且必须 finally 里 unlock。大数据框架源码里两者都常见,比如 Kafka 的 buffer pool 用 ReentrantLock + Condition 做内存不足时的等待唤醒,就是看中多条件队列。
可能的追问
- 偏向锁为什么要等到安全点才能撤销? 撤销要检查持有线程的栈帧状态,必须线程停下来才能保证看到一致的视图,所以会有短暂 STW,高并发下撤销频繁就成了性能负担。
- 自旋锁为什么还需要重量级锁兜底? 自旋是空转 CPU,持有锁的线程如果迟迟不释放,自旋线程白烧 CPU;而且自旋线程多了会互相抢总线。自适应自旋失败上限到了就升级,让线程去睡觉。
- 锁粗化和锁消除举个实际例子? StringBuffer 的连续 append 会被粗化成一次加锁;方法内 new 的 StringBuffer 不逃逸,锁直接被消除。这也是「线程安全的局部类在 JIT 下不一定有锁开销」的原因。
- synchronized 修饰静态方法和实例方法的区别? 静态方法锁的是 Class 对象,全局一把锁;实例方法锁的是 this,每个实例一把锁。混用时两类锁互不干扰,要注意是不是真想要这个语义。