Happens-before原则
JMM的定义是通过动作的形式来描述的,所谓动作,包括变量的读和写,监视器加锁和释放锁,线程的启动和拼接,这就是传说中的happen before,要想A动作看到B动作的结果,B和A必须满足happen before关系。
是一种可见性规则,它表达的含义是前面一个操作的结 果对后续操作是可见的,是对编译器和处理器重排序的规则
Happens-before规则
从JDK5开始,java使用新的JSR -133内存模型(本文除非特别说明,针对的都是JSR- 133内存模型)。JSR-133提出了happens-before的概念,通过这个概念来阐述操作之间的内存可见性。如果一个操作执行的结果需要对另一个操作可见,那么这两个操作之间必须存在happens-before关系。这里提到的两个操作既可以是在一个线程之内,也可以是在不同线程之间。 与程序员密切相关的happens-before规则如下:
- 程序顺序规则:在一个单独的线程中,按照程序代码的执行流顺序,(时间上)先执行的操作happen—before(时间上)后执行的操作。
- 监视器锁规则:一个unlock操作happen—before后面(时间上的先后顺序,下同)对同一个锁的lock操作。
- volatile变量规则:对一个volatile变量的写操作happen—before后面对该变量的读操作
- 传递性规则:如果A happens-before于B,B happens-before于C,那么A happens-before于C
- 线程启动规则:Thread对象的start()方法happen—before此线程的每一个动作。(扩:假如线程A执行中调用B.start(),线程A对共享变量修改B知道)
- 线程中断规则:对线程interrupt()方法的调用happen—before发生于被中断线程的代码检测到中断时事件的发生。(扩:线程A写入的变量,调用Thread.interrupt(),被打断的线程B可以看到A的操作)
- 线程终结规则:线程的所有操作都happen—before对此线程的终止检测,可以通过Thread.join()方法结束、Thread.isAlive()的返回值等手段检测到线程已经终止执行。(线程A写入的变量,在任意线程B调用A.join()或A.isALive()成功后,对B可见)
- 对象终结规则:一个对象的初始化完成(构造函数执行结束)happen—before它的finalize()方法的开始。
注意,两个操作之间具有happens-before关系,并不意味着前一个操作必须要在后一个操作之前执行!happens-before仅仅要求前一个操作(执行的结果)对后一个操作可见,且前一个操作按顺序排在第二个操作之前(the first is visible to and ordered before the second)。这样的重排序也是可以的
happens-before与JMM的关系
如上图所示,一个happens-before规则通常对应于多个编译器重排序规则和处理器重排序规则。对于java程序员来说,happens-before规则简单易懂,它避免程序员为了理解JMM提供的内存可见性保证而去学习复杂的重排序规则以及这些规则的具体实现。