happen-before是JMM最外围的概念,所以在理解happen-before准则之前,首先须要理解java的内存模型。
JMM内存模型
java内存模型是共享内存的并发模型,线程之间次要通过读-写共享变量来实现隐式通信。java中的共享变量是存储在内存中的,多个线程由其工作内存,其工作形式是将共享内存中的变量拿进去放在工作内存,操作实现后,再将最新的变量放回共享变量,这时其余的线程就能够获取到最新的共享变量。
从横向去看看,线程A和线程B就如同通过共享变量在进行隐式通信。这其中有很有意思的问题,如果线程A更新后数据并没有及时写回到主存,而此时线程B读到的是过期的数据,这就呈现了 “脏读” 景象。 为防止脏读,能够通过同步机制(管制不同线程间操作产生的绝对程序)来解决或者通过volatile关键字使得每次volatile变量都可能强制刷新到主存,从而对每个线程都是可见的。
重排序
在执行程序时,为了进步性能,编译器和处理器经常会对指令进行重排序。个别重排序能够分为如下三种:如图,1属于编译器重排序,而2和3统称为处理器重排序。
这些重排序会导致线程平安的问题,一个很经典的例子就是DCL问题。JMM的编译器重排序规定会禁止一些特定类型的编译器重排序;针对处理器重排序,编译器在生成指令序列的时候会通过插入内存屏障指令来禁止某些非凡的处理器重排序。
(1)编译器优化的重排序。编译器在不扭转单线程程序语义的前提下,能够重新安排语句的执行程序;
(2)指令级并行的重排序。古代处理器采纳了指令级并行技术来将多条指令重叠执行。如果不存在数据依赖性,处理器能够扭转语句对应机器指令的执行程序;
(3)内存零碎的重排序。因为处理器应用缓存和读/写缓冲区,这使得加载和存储操作看上去可能是在乱序执行的。
举个例子:
因为A,B之间没有任何关系,对最终后果也不会存在关系,它们之间执行程序能够重排序。因而能够执行程序能够是A->B->C或者B->A->C执行最终后果都是3.14,即A和B之间没有数据依赖性。
什么是happen-before
JMM能够通过happens-before关系向程序员提供跨线程的内存可见性保障(如果A线程的写操作a与B线程的读操作b之间存在happens-before关系,只管a操作和b操作在不同的线程中执行,但JMM向程序员保障a操作将对b操作可见)。
具体的定义为:
1)如果一个操作happens-before另一个操作,那么第一个操作的执行后果将对第二个操作可见,而且第一个操作的执行程序排在第二个操作之前。
2)两个操作之间存在happens-before关系,并不意味着Java平台的具体实现必须要依照happens-before关系指定的程序来执行。如果重排序之后的执行后果,与按happens-before关系来执行的后果统一,那么这种重排序并不非法(也就是说,JMM容许这种重排序)。
具体的规定:
(1)程序程序规定:一个线程中的每个操作,happens-before于该线程中的任意后续操作。
(2)监视器锁规定:对一个锁的解锁,happens-before于随后对这个锁的加锁。
(3)volatile变量规定:对一个volatile域的写,happens-before于任意后续对这个volatile域的读。
(4)传递性:如果A happens-before B,且B happens-before C,那么A happens-before C。
(5)start()规定:如果线程A执行操作ThreadB.start()(启动线程B),那么A线程的ThreadB.start()操作happens-before于线程B中的任意操作。
(6)Join()规定:如果线程A执行操作ThreadB.join()并胜利返回,那么线程B中的任意操作happens-before于线程A从ThreadB.join()操作胜利返回。
(7)程序中断规定:对线程interrupted()办法的调用后行于被中断线程的代码检测到中断工夫的产生。
(8)对象finalize规定:一个对象的初始化实现(构造函数执行完结)后行于产生它的finalize()办法的开始。
利用程序程序规定(规定1)存在三个happens-before关系:
A happens-before B;
B happens-before C;
A happens-before C。
这里的第三个关系是利用传递性进行推论的。这里的第三个关系是利用传递性进行推论的。
A happens-before B,定义1要求A执行后果对B可见,并且A操作的执行程序在B操作之前,但与此同时利用定义中的第二条,A,B操作彼此不存在数据依赖性,两个操作的执行程序对最终后果都不会产生影响,在不扭转最终后果的前提下,容许A,B两个操作重排序,即happens-before关系并不代表了最终的执行程序。