synchronized锁升级通过降低线程切换与缓存行失效频率来减少缓存一致性压力:偏向锁使单线程独占缓存数据,轻量级锁用自旋避免内核态切换,重量级锁虽开销大但收敛竞争、提升缓存局部性。

synchronized 锁升级过程本身不直接操作 CPU 缓存,但它通过改变线程调度方式和内存同步策略,间接影响 CPU 缓存的使用行为和一致性开销。
锁升级如何减少缓存一致性压力
在低竞争场景下,偏向锁和轻量级锁避免了线程阻塞与内核态切换,也就避免了因线程挂起/唤醒导致的缓存行失效(cache line invalidation)风暴。比如:多个线程反复争抢同一把重量级锁时,OS 调度器频繁切换线程,每个新线程被调度到不同 CPU 核心上执行,会触发 MESI 协议下的大量缓存行状态迁移(如从 Shared → Invalid),造成总线流量上升和缓存延迟增加。而偏向锁让单一线程长期持有锁,其工作内存数据持续驻留在该核心的 L1/L2 缓存中,显著降低跨核缓存同步频率。
不同锁状态对内存屏障的实际作用
synchronized 块的进入和退出始终隐含内存屏障语义,但具体屏障强度随锁级别动态调整:
- 偏向锁:不引入额外屏障;仅靠对象头 mark word 的 CAS 更新保证原子性,读写仍依赖 JVM 默认的 happens-before 关系,缓存可见性由后续 unlock 时的写屏障兜底。
- 轻量级锁:自旋期间不刷新缓存,但竞争失败后升级时,会插入读屏障(确保重读共享变量)和写屏障(确保本地修改刷回主存),强制同步缓存行。
- 重量级锁:monitor enter/exit 显式插入全内存屏障(LoadStore + StoreLoad),强制清空 store buffer、刷新 write queue,使当前核心缓存中的相关变量全部写回 L3 缓存或主存,再通知其他核心作缓存行失效 —— 这是 CPU 缓存一致性开销最大的环节。
对象头 mark word 与缓存行对齐的隐性影响
HotSpot 中对象头(含 mark word)位于对象起始地址,而 CPU 缓存行通常是 64 字节。当多个高频访问的对象(如链表节点、队列元素)在堆中连续分配,且它们的 mark word 都被频繁读写(如锁升级/降级判断),就可能引发“伪共享”(false sharing):一个缓存行里挤着多个对象的 mark word,一个对象加锁导致整行被标记为 Modified,其他对象即使没被修改也会被迫重新加载 —— 这种干扰在轻量级锁自旋阶段尤为明显。实践中可通过对象填充(@Contended)或调整对象分配策略缓解。
为什么高并发时反而更“省缓存”?
看似矛盾,实则合理:重量级锁虽带来单次高开销,但它把原本分散、不可预测的自旋竞争,收敛为集中、可控的阻塞队列管理。线程挂起后不再占用 CPU 执行单元,也不再反复尝试 CAS 更新 mark word,从而停止对缓存行的无效争抢。此时缓存资源被真正执行的线程独占使用,整体缓存局部性反而提升。换句话说,锁升级不是“越升越耗缓存”,而是用一次确定性开销,换取持续的缓存友好性。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











