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