根本前提是必须严格遵守as-if-serial语义:单线程执行结果必须与代码串行执行结果完全一致;它只约束单线程行为,不保证多线程间可见性,而happens-before则在跨线程场景中建立有序性和可见性保障。

Java 内存模型中,多线程环境下允许指令重排的**根本前提**,是它必须严格遵守 as-if-serial 语义:即无论编译器、JVM 还是 CPU 如何重排指令,**单线程的执行结果,必须与按代码书写顺序串行执行的结果完全一致**。
as-if-serial 语义的核心要求
这不是一个可选优化策略,而是强制约束。只要满足以下两点,重排才被允许:
- 不改变单线程的程序行为:所有读写操作的最终效果(如变量值、I/O 输出、异常抛出时机等)必须和原始代码顺序执行时一模一样;
-
只对无数据依赖的指令重排:比如
a = 1;和b = 2;可以互换,因为彼此不读写对方变量;但a = 1;和c = a + 1;就不能颠倒,否则c会读到未初始化的a。
为什么这个条件只保单线程,不管多线程?
as-if-serial 只关注“单个线程看起来像串行执行”,它不关心多个线程之间如何看到彼此的操作。也就是说:
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
- 线程 A 内部重排后,A 自己看到的 a、b、flag 等变量变化顺序可以变,但 A 最终看到的结果不变;
- 但线程 B 可能在线程 A 重排后的某个中间状态读取共享变量——比如 A 把
instance = new Singleton()拆成“分配内存→设置引用→初始化字段”,而重排后“设置引用”提前,B 就可能拿到一个未初始化完成的对象。
它和 happens-before 的关系
as-if-serial 是重排的“底线”,happens-before 是多线程下的“护栏”:
- as-if-serial 允许重排,但禁止破坏单线程逻辑;
- happens-before 规则(如 volatile 写读、锁的释放与获取、start/join)则在跨线程场景中,人为建立操作间的先后约束,从而“压制”可能破坏可见性或有序性的重排。
换句话说:没有 as-if-serial,连单线程都不可靠;没有 happens-before,多线程就不可控。两者共同构成 Java 并发安全的底层契约。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










