happens-before
JMM的设计
JMM的设计维持一个平衡点:既要让开发人员提供足够强的内存可见性保证,同时要对编译器和处理器的限制要尽可能地放松。
JMM两种重排序策略
- 对于会改变程序执行结果的重排序,JMM要求编译器和处理器必须禁止这种重排序;
- 对于不会改变程序执行结果的重排序,JMM对编译器和处理器不做要求(即允许重排序)

实际,happens-before关系本质上和as-if-serial语义是一回事,辨析如下:
- as-if-serial语义保证单线程内程序的执行结果不被改变,happens-before关系保证正确同步的多线程程序的执行结果不被改变;
- as-if-serial语义给编写单线程程序的程序员创造了一个幻境:单线程程序是按照程序的顺序来执行的。happens-before关系给编写多线程程序的程序员另一个幻境:正确同步的多线程程序是按照happens-before指定的顺序执行的。
Java 内存模型综述
根据对不同类型的读/写操作组合的执行顺序的放松,将常见处理器内存模型划分如下:
- 放松程序中写-读操作的顺序,由此产生了Total Store Ordering内存模型(简称TSO);
- 在上面的基础上,继续放松程序中写-写操作的顺序,由此产生了Partial Store Order内存模型(简称PSO);
- 在前两条的基础上,继续放松程序中读-写和读-读操作的顺序,由此产生了Relaxed Memory Order内存模型(简称为RMO)和PowerPC内存模型。
处理器内存模型的特征表如下:
| 内存模型名称 | 对应的处理器 | Stored-Load重排序 | Store-Store重排序 | Load-Load和Load-Store重排序 | 可以更早读取到其他处理器的写 | 可以更早读取到当前处理器的写 |
|---|---|---|---|---|---|---|
| TSO | sparc-TSO X64 | Y | Y | |||
| PSO | sparc-PSO | Y | Y | Y | ||
| RMO | ia64 | Y | Y | Y | Y | |
| PowerPC | PowerPC | Y | Y | Y | Y | Y |
JMM的内存可见性保证
- 单线程程序。单线程程序不会出现内存可见性问题。编译器、runtime和处理器会共同确保单线程程序的执行结果与改程序在顺序一致性模型中的执行结果相同;
- 正确同步带额多线程程序。正确同步的多线程程序的执行将具有顺序一致性(程序的执行结果与改程序在顺序一致性内存模型中的执行结果相同)。这是JMM关注重点,JMM通过限制编译器和处理器的重排序来为程序员提供内存可见性保证。
- 未同步/未正确同步的多线程程序。JMM为它们提供了最小安全性保障:线程执行时读取到的值,要么是之前某个线程写入的值,要么是默认值(0,null,false)。
注意最小安全保障与64位数据的非原子性写并不矛盾,最小安全性保障对象默认初始化后才会被任意线程使用,最小安全性“发生”在对象被任意线程使用之前。64位数据的非原子性写“发生”在对象被任意线程使用的过程中(写共享变量)