锁粗化是jvm jit编译器自动将同一锁对象的连续同步操作合并为单次大范围同步的优化策略,旨在减少monitorenter/monitorexit指令、cas、内存屏障及线程状态切换等开销,提升吞吐量。

锁粗化是 JVM 在 JIT 编译阶段自动执行的一种优化策略,它不改变程序逻辑,而是把原本分散、频繁的加锁/解锁操作合并成一次范围更大的同步块,从而减少锁操作本身的开销。
锁粗化的核心目的
避免在同一个对象上反复申请和释放锁。每次加锁解锁都涉及 Monitor 进入/退出、计数器维护、可能的线程状态切换等成本,尤其在循环或连续调用中,这些开销会累积放大。
- 减少 monitorenter / monitorexit 字节码指令的执行次数
- 降低与操作系统互斥原语(如 mutex)交互的频率
- 缓解因高频锁操作引发的上下文切换或竞争加剧
典型触发场景
当 JVM 发现对同一锁对象的多次同步操作在代码上“紧邻”且无实质异步逻辑插入时,就会考虑粗化。
- 连续的同步方法调用:比如对同一个 StringBuffer 实例反复调用 append(),每个 append() 都是 synchronized 方法;JVM 可能将整个调用序列包裹进一个大的 synchronized 块
- 循环体内的同步块:for 循环中每次迭代都对同一对象加锁,且循环内无其他线程可见副作用时,锁可能被提升到循环外
- 相邻的同步代码块:两个或多个 synchronized(this) { ... } 块之间没有非同步代码分隔,且锁对象相同
粗化不是无条件的
JVM 不会盲目扩大锁范围——它必须确保粗化后仍满足原有语义,即不引入新的线程安全问题。
- 若同步块之间存在可能被其他线程读取或修改的共享状态,粗化会被跳过
- 若锁对象在不同同步块中实际不同(比如 this 和 new Object() 混用),不会合并
- 逃逸分析结果会影响判断:如果锁对象本身可被多线程访问,粗化仍可能发生;但若对象不可逃逸,JVM 更倾向直接消除锁而非粗化
如何观察锁粗化效果
它属于 JIT 编译器的透明优化,开发者无法显式控制,但可通过工具间接验证:
- 使用 -XX:+PrintCompilation 查看方法是否被 JIT 编译
- 配合 -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly(需 hsdis)查看生成的汇编,对比粗化前后的 monitor 指令密度
- 性能对比:对含高频小同步块的代码做基准测试,开启/关闭 JIT(如 -Xint)可感知差异
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











