Happens-Before 是一种可见性模型,也就是说,在多线程环境下。
本来因为指令重排序的存在会导致数据的可见性问题,也就是 A 线程批改某个共享变量 对 B 线程不可见。
因而,JMM 通过 Happens-Before 关系向开发人员提供逾越线程的内存可见性保障。
如果一个操作的执行后果对另外一个操作可见,那么这两个操作之间必然存在 Happens-Before 关系。
其次,Happens-Before 关系只是形容后果的可见性,并不示意指令执行的先后顺序,也就是说 只有不对后果产生影响,依然容许指令的重排序。
happens-before 准则定义如下:
1. 如果一个操作 happens-before 另一个操作,那么第一个操作的执行后果将对第二个操作可见,而且第一个操作的执行程序排在第二个操作之前。
2. 两个操作之间存在 happens-before 关系,并不意味着肯定要依照 happens-before 准则制订的程序来执行。如果重排序之后的执行后果与依照 happens-before 关系来执行的后果统一,那么这种重排序并不非法。
JMM 中的 happens-before 准则:
- 程序秩序规定:一个线程中的每个操作,happens-before 这个线程中的任意后续操作;这个规定只对单线程无效,在多线程环境下无奈保障正确性。
- 监视器锁规定:一个线程对于一个锁的开释锁操作,肯定 happens-before 于后续线程对这个锁的加锁操作;
- volatile 变量规定:对一个 volatile 润饰的变量的写肯定 happens-before 于任意后续对这个 volatile 变量的读操作;
- 传递规定:如果 A happens-before B,且 B happens-before C,那么 A happens-before C。
- 线程启动规定:如果线程 A 执行操作 ThreadB.start(), 那么线程 A 的 ThreadB.start() 之前的操作 happens-before 线程 B 中的任意操作;
在这样一个场景中,t1 线程启动之前对于 x=10 的赋值操作,t1 线程启动当前读取 x 的值肯定是 10
- 线程终结规定(join 规定):如果线程 A 执行操作 ThreadB.join() 并胜利返回,那么线程 B 中的任意操作 happens-before 于线程 A 从 ThreadB.join() 操作胜利的返回。;
(假设线程 A 在执行的过程中,通过制订 ThreadB.join() 期待线程 B 终止,那么线程 B 在终止之前对共享变量的批改在线程 A 期待返回后可见。)
- 线程中断规定:对线程 interrupted() 办法的调用后行于被中断线程的代码检测到中断事件的产生。
- 对象终结规定:一个对象的初始化实现(构造函数执行完结)后行于产生它的 finalize() 办法的开始。
happen-before 准则是 JMM 中十分重要的准则,它是判断数据是否存在竞争、线程是否平安的次要根据,保障了多线程环境下的可见性。