程序次序规则是happens-before的基础,仅在单线程内生效,要求重排序后语义等价于源码顺序,定义逻辑先后而非物理时间先后。

程序次序规则是 happens-before 的基础,它只在单线程内生效,不跨线程起作用,但它为所有其他规则(比如锁、volatile)提供了逻辑起点。
它不是强制按代码顺序执行
这条规则不禁止编译器或 CPU 重排序,而是要求:重排序后的执行效果,必须和按源码顺序执行的结果一致。换句话说,只要语义等价,怎么排都行。
- 比如 a = 1; b = a + 1;,JVM 可能把 b = a + 1 提前计算,但必须确保 a 已赋值为 1,否则就破坏了依赖关系
- 再如 x = 42; flag = true;,即使 flag = true 被提前写入,x = 42 的结果也必须对后续读 x 的操作可见——这是单线程行为可预测的底线
它定义的是“逻辑先后”,不是“物理时间先后”
这里的“前面”“后面”指控制流顺序,不是字面位置。比如 if 分支、循环体内的语句,实际执行顺序取决于运行时条件,但一旦某条语句被执行,它就对同一分支中后续执行的语句 happens-before。
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
- if (cond) { x = 1; y = 2; } else { x = 3; } —— 在进入 if 分支后,x = 1 happens-before y = 2;在进入 else 分支后,x = 3 独立成立,不与 if 中语句构成 happens-before
- for (int i = 0; i
它是跨线程可见性的前提,但本身不提供跨线程保证
单靠程序次序规则,无法让线程 A 的写操作对线程 B 可见。它只是说:A 内部,写操作 A1 happens-before 写操作 A2;B 内部,读操作 B1 happens-before 读操作 B2。但 A1 和 B1 之间没有任何 happens-before 关系,除非通过锁、volatile、start/join 等其他规则连接。
- 典型反例:线程 A: x = 1; flag = true;,线程 B: if (flag) print(x); —— 即使 A 中 x 先于 flag 写入,B 仍可能看到 flag == true 但 x == 0,因为缺少同步机制建立跨线程 happens-before 链
- 要让 B 看到 x == 1,必须补上一条链,比如把 flag 声明为 volatile(触发 volatile 规则),或把两行写入放在 synchronized 块里(触发管程锁定规则)
不复杂但容易忽略
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










