synchronized通过happens-before规则和内存屏障约束指令重排,而非禁止所有重排:解锁happens-before后续加锁,进入/退出同步块时插入loadload、loadstore、storestore、storeload屏障,仅保障边界有序性,不干预临界区内部重排。

synchronized 通过建立 happens-before 关系和插入内存屏障,强制约束指令执行顺序,从而保证有序性。
有序性问题的根源
多线程环境下,编译器优化和 CPU 乱序执行可能导致代码实际执行顺序与源码顺序不一致。例如:
- 线程 A 写入变量 x = 1,再写入 flag = true;
- 线程 B 检查 flag == true 后读取 x;
- 若无同步,B 可能看到 flag 为 true,但 x 仍为 0(指令重排导致 flag 先于 x 写入主存)。
synchronized 如何建立执行顺序约束
它不靠“按行执行”,而是借助 Java 内存模型(JMM)定义的 happens-before 规则:
- 对同一个锁,解锁操作(unlock)happens-before 后续对该锁的加锁操作(lock);
- 进入 synchronized 块前的所有操作,对进入该块的线程可见且有序;
- 退出 synchronized 块后的所有操作,不会被重排到块内执行。
这相当于在同步块入口和出口处各插入一个全内存屏障(Full Memory Barrier),禁止屏障两侧的读写指令跨越边界重排。
实际效果示例
以下代码中,synchronized 确保 init() 中的初始化动作全部完成,且对后续调用者可见:
private static volatile boolean inited = false;
private static Resource resource;
public static void init() {
synchronized (Resource.class) {
if (!inited) {
resource = new Resource(); // 步骤1
inited = true; // 步骤2
}
}
}
即使编译器或 CPU 尝试将步骤2提前,也会被内存屏障拦截——步骤1的写入一定先于步骤2对其他线程可见。
与 volatile 的区别
volatile 仅禁止其修饰变量自身的读写重排;synchronized 则对整个同步块内的所有内存操作施加顺序约束,覆盖更广、力度更强,但也带来更大开销。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











