Skip to content

P38 synchronized 怎么提升性能 ​

面试题:synchronized 不是"重量级锁"吗?JVM 做了哪些优化来提升它的性能?

答案核心:从重量级到轻量级的锁升级 ​

Java 6 之后 synchronized 通过**锁升级(无锁 → 偏向锁 → 轻量级锁 → 重量级锁)**大幅优化性能,只有在真正有竞争时才变成重量级。

1. 锁升级过程 ​

text
无锁 → 偏向锁 → 轻量级锁(自旋)→ 重量级锁(阻塞)

① 偏向锁 ​

  • 同一个线程反复进入同步块时,无需任何 CAS/竞争开销;
  • 锁记录偏向第一个获得它的线程,后续该线程再次进入直接通过(记录在 Mark Word);
  • 有其他线程竞争时撤销偏向锁(需要停顿,Java 15 默认禁用偏向锁,之后版本逐步移除)。

② 轻量级锁 + 自旋 ​

  • 竞争不激烈时,用 CAS 在栈帧中记录锁记录,而不是阻塞线程;
  • 拿不到锁的线程自旋等待(默认自旋次数/自适应),避免线程上下文切换;
  • 自旋超过阈值或竞争激烈 → 膨胀为重量级锁。

③ 重量级锁 ​

  • 依赖操作系统互斥量(Monitor),线程拿不到锁进入阻塞队列,涉及用户态/内核态切换,成本最高;
  • 锁只能这样兜底:高并发激烈竞争时保证正确性。

2. 其他优化 ​

  • 锁粗化(Lock Coarsening):连续多次加同一把锁,合并成一次加锁;
  • 锁消除(Lock Elimination):JIT 分析发现锁对象不会被其他线程共享(逃逸分析),直接去掉加锁;
  • 自适应自旋(Adaptive Spinning):JVM 根据上次自旋成功情况动态调整自旋次数。

3. 开发者侧优化 ​

  • 缩小锁粒度:只锁必要代码块;
  • 减小锁持有时间:不要在锁里做 IO、远程调用;
  • 读写分离场景用 ReentrantReadWriteLock/StampedLock 代替全互斥;
  • 无锁优先:Atomic 类、volatile、ThreadLocal、不可变对象;
  • 合理选择:竞争极低用 synchronized(简单),需要超时/可中断/公平用 Lock。

4. 加分点 ​

  • 说出 Mark Word 存锁状态(偏向线程 ID / 锁记录指针 / Monitor 指针);
  • 说明"偏向锁不是锁,是免锁",撤销偏向锁成本高所以高并发下可能关掉它;
  • 追问"什么情况下直接重量级":竞争激烈、自旋失败、锁长时间占用。

一句话总结 ​

synchronized 性能靠 JVM 的锁升级(偏向 → 轻量级自旋 → 重量级)和锁粗化/锁消除/自适应自旋优化,平时几乎没有竞争开销;开发者再配合缩小锁粒度、减少锁内耗时,性能完全够用。

基于 VitePress 重建