锁粗化是JIT编译器自动将多个相邻且针对同一对象的synchronized块合并为一个同步区域的优化技术,以减少加锁/解锁开销,需满足锁对象相同、无副作用、代码紧邻等条件。

Java 锁粗化(Lock Coarsening)是 JIT 编译器在运行时自动优化的一种技术,它不会要求你手动“在循环体内合并加锁操作”,而是由 HotSpot JVM 在满足条件时,将多个相邻的、针对同一对象的同步块(synchronized)自动合并为一个更长的同步区域,从而减少加锁/解锁的开销。
锁粗化的触发条件
JIT 编译器(如 C2)在方法内联和逃逸分析之后,若发现以下情况,可能执行锁粗化:
- 多个
synchronized块作用于**同一个对象**(或同一把锁),且中间没有其他线程可见的副作用(如非 volatile 写、I/O、锁释放、线程通信等); - 这些同步块在**代码上连续或逻辑上紧邻**(例如在同一个循环体内反复出现);
- 锁对象未发生逃逸(即被判定为线程私有),或即使逃逸,但编译器能证明多处加锁实际互不干扰(较罕见)。
典型可被粗化的循环模式
下面这段代码是锁粗化的常见目标:
synchronized (lock) {
list.add(1);
}
synchronized (lock) {
list.add(2);
}
synchronized (lock) {
list.add(3);
}
JIT 可能将其优化为:
立即学习“Java免费学习笔记(深入)”;
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
synchronized (lock) {
list.add(1);
list.add(2);
list.add(3);
}
同理,对循环体内的单步加锁:
for (int i = 0; i < 100; i++) {
synchronized (lock) {
list.add(i);
}
}
在满足逃逸分析与无副作用的前提下,JIT 可能粗化为:
synchronized (lock) {
for (int i = 0; i < 100; i++) {
list.add(i);
}
}
你不能也不该“手动合并”来“帮助”粗化
锁粗化是运行时优化,开发者无需、也不应为了触发它而刻意改写循环结构。原因包括:
- 粗化是否发生取决于 JIT 的编译时机、层级(C1/C2)、逃逸分析结果、锁竞争状况等,不可控;
- 手动把整个循环包进一个
synchronized块,反而会显著扩大临界区,增加线程阻塞风险,降低并发度; - 若循环体中包含 I/O、远程调用、耗时计算或其它锁操作,粗化不仅不会发生,强行合并还会严重损害性能和响应性。
真正有效的替代方案
比起依赖锁粗化,更可靠的做法是:
-
减少锁粒度:用
ConcurrentHashMap、CopyOnWriteArrayList等线程安全集合替代手动加锁; - 缩小临界区:只在真正需要保护共享状态的最小代码段加锁,避免在锁内做格式化、日志、网络请求等;
-
使用分段锁或读写锁:如
ReentrantReadWriteLock,允许多读并发; -
考虑无锁编程:对简单计数器等场景,优先用
AtomicInteger、LongAdder等。
锁粗化是 JVM 的“锦上添花”,不是并发设计的基石。写正确、低竞争、小临界区的同步逻辑,比期待 JIT 合并锁更实在。

















