happens-before 是用于保证操作结果的可见性而非时间先后顺序;它通过程序顺序、volatile变量、监视器锁、线程启动/终止等八大规则建立传递链,确保前序写入对后续读取可见且禁止破坏该关系。

happens-before 不是用来判断“谁先执行”的时间先后,而是用来确定“一个操作的结果对另一个操作是否可见”。只要两个操作之间能通过八大规则之一(或其传递链)建立 happens-before 关系,JVM 就必须保证前者的写入对后者可见,且禁止重排序破坏该关系。
程序顺序规则:单线程内的天然顺序保障
同一个线程中,代码在控制流上的前面操作 happens-before 后面操作。这包括顺序、分支、循环中的逻辑顺序,不等于字面行号,但等价于程序员可预期的执行路径。
- 例如:
i = 1;→flag = true;,即使编译器或 CPU 重排指令,i=1的结果也一定对flag=true之后的同线程读取可见 - 注意:它只约束单线程,不提供跨线程可见性
volatile 变量规则:轻量级的跨线程同步锚点
对 volatile 变量的写操作 happens-before 后续任意线程对该变量的读操作。这是构建跨线程通信链最常用的一环。
- 典型用法:用 volatile 布尔标志触发状态切换,配合程序顺序规则传递其他变量的值
- 示例:线程 A 执行
data = 42; ready = true;(ready是 volatile),线程 B 读到ready == true,就能安全读到data == 42—— 因为data=42 → ready=true → B 读 ready形成传递链
监视器锁规则:synchronized 的内存语义基础
对同一把锁,unlock 操作 happens-before 后续对该锁的 lock 操作。这意味着临界区退出时的写入,对下一个进入该临界区的线程可见。
- 关键点是“同一把锁”和“后续”(时间上后发生,不一定是代码写在后面)
- 比如:线程 A 释放
lock前修改了共享变量count;线程 B 成功获取同一lock后,一定能见到更新后的count - 注意:synchronized 块的 enter 和 exit 都有内存屏障,不只是 unlock 有作用
线程启动与终止规则:start() 和 join() 的隐含契约
thread.start() happens-before 新线程的任何操作;新线程的所有操作 happens-before 其他线程成功返回 thread.join()。
- 启动规则确保主线程在
start()前设置的共享变量,对子线程初始执行可见 - 终止规则让主线程在
join()返回后,能安全读取子线程写入的最终结果(如统计值、状态标记等) - 这两个规则常被忽略,却是正确使用线程协作的基础

















