程序顺序规则不禁止重排序,而是基于as-if-serial语义保证单线程内执行结果等价于按代码顺序执行;它仅约束同一线程内操作的happens-before关系,不提供跨线程可见性。

程序顺序规则本身不“保证”代码按字面顺序执行,而是保证单线程内操作的结果可见性与逻辑一致性——即使编译器或 CPU 重排序,你看到的行为也等价于按代码书写顺序执行。
它靠的是“as-if-serial”语义,不是禁止重排
Java 虚拟机和底层硬件可以对指令重排序,但前提是不能改变本线程中任意正确同步程序的执行结果。也就是说:
- 只要重排不影响该线程内部的读写依赖和控制流逻辑,就允许发生
- 比如
i = 1; flag = true;可能被重排为先写flag,但后续在同一线程里读i时,仍一定能见到i == 1 - 这种保障不是靠锁或内存屏障,而是 JVM 的执行模型强制约定
顺序由控制流定义,不等于行号顺序
程序顺序规则中的“先后”,依据的是代码在控制流中的实际执行路径:
- 顺序结构:A 在 B 前面 → A happens-before B
- 分支结构:if 分支内语句之间仍满足程序顺序;不同分支之间无 happens-before 关系
- 循环结构:每次迭代内部保持顺序,迭代之间也按执行次序链式传递
- 例如:
if (cond) { x = 1; y = 2; }中,x=1 对 y=2 是 happens-before;但 cond 为 false 时,这两条语句根本不执行,自然不构成关系
它只管单线程,不管其他线程看到什么
这个规则是线程内行为的基石,但有重要边界:
- 它确保线程 A 内部:A1 → A2 → A3 的写入对 A 自身后续读取可见
- 但它完全不保证线程 B 能否及时看到 A 的写入——跨线程可见性必须靠 volatile、synchronized、join 等其他规则补足
- 常见误解:以为 “i=1; j=2;” 在线程 A 中执行了,线程 B 读 j 就一定能看到 i=1 —— 这是错的,除非有额外同步手段建立跨线程 happens-before 链
它是其他 happens-before 规则的起点
几乎所有跨线程通信都依赖程序顺序规则打底:
- volatile 写后读:线程 A 的
data = 42; ready = true;(ready 是 volatile)→ 因为程序顺序,data=42 happens-before ready=true;再叠加 volatile 规则,ready=true happens-before 线程 B 读 ready → 传递得出 data=42 对 B 可见 - synchronized 块内操作:临界区内的所有语句天然满足程序顺序,再通过监视器锁规则向外传递可见性
- thread.start() 前的初始化:主线程中 start() 前的赋值,靠程序顺序 + 启动规则,对子线程初始执行可见
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











