https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.4
Happens-before 的定义
通过上面的定义,我们得出 happens-before 的原则:
happens-before 定义了什么时候会发生数据争用(即:多线程读取共享变量)。
happens-before 原则:
1. 对锁(对象监视器)的 释放(unlock)操作 happens-before 锁的 lock 操作
2. 对 volatile 字段的写操作 happens-before 对这个字段的读操作
从底层实现来看,volatile 写操作会通过汇编中的 lock 前缀指令,对这块内存区域的缓存行进行锁定,
这样,如果此时正在对 volatile 变量时行写操作,那么其他线程所有的读操作都需要等待写操作完成,这就是 volatile 写操作 happens-before 对这个字段读操作的原因
3. 对线程的 start() 的调用 happens-before 这个线程里面的代码的执行
4. t1.join() 成功后,那么 t1 线程里面的代码的执行 happens-before main 线程
5. 一个对象默认的初始化操作 happens-before 这个程序里面的其他操作
当一个程序包含两个冲突的访问,且这两个访问没有按照 happens-before 原则进行排序,那么,我们称之为数据争用。
线程间操作以外的操作的语义,例如,读取数组长度、执行已检查的强制转换,以及调用虚拟方法,不会直接影响数据争用。
当且仅当所有顺序一致的执行都没有数据争用时,程序才能正确同步。
如果一个程序正确同步,则该程序的所有执行将看起来是顺序一致的。
这是对程序员的极其有力的保证。程序员无需考虑重排序(指令重排)即可确定其代码包含数据争用。因此,在确定其代码是否正确同步时,他们无需考虑指令重排。一旦确定代码正确同步,程序员就不必担心指令重排会影响他的代码。
一个程序必须正确的同步,从而避免在指令重排时得到意想不到的结果。使用正确的同步不能确保程序的整体行为正确。但是,同步的使用让程序员可以以一种简单的方式来推理程序的可能行为。正确同步的程序的行为很少依赖于可能的指令重排。没有正确同步的程序,就可能得到非常奇怪、令人困惑和违反直觉的结果。