什么是happens before
“Happens before”是由Leslie Lamport引入的用来描述程序事件的一种偏序关系。
用通俗的话来说就是,我们定义系列规则保证A线程修改变量什么时候对线程B是可见的,这种规则
可以抽象出来happens-before。
概要
happens-before是JMM最核心的概念,理解happens-before是理解JMM的关键,
JSR-133使用happens-before的概念来指定两个操作之间的执行顺序。由于这两个操作可以在一个线程之内,
也可以是在不同线程之间。因此,JMM可以通过happens-before关系向程序员提供跨线程的内存可见性保证
(如果A线程的写操作a与B线程的读操作b之间存在happensbefore关系,尽管a操作和b操作在不同的线程中执行,
但JMM向程序员保证a操作将对b操作可见
定义
如果一个操作happens-before另一个操作,那么第一个操作的执行结果将对第二个操作可见,
而且第一个操作的执行顺序排在第二个操作之前
两个操作之间存在happens-before关系,并不意味着Java平台的具体实现必须要按照happens-before关系指定的顺序来执行。
如果重排序之后的执行结果,与按happens-before关系来执行的结果一致,那么这种重排序并不非法。
Happens-Before原则是判断数据是否存在竞争、线程是否安全的主要依据
Java内存模型下Happens-Before规则
1、程序顺序规则:一个线程中的每个操作,happens-before于该线程中的任意后续操作
2、监视器锁规则:对一个锁的解锁,happens-before于随后对这个锁的加锁(符合synchronized的可见性)
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()操作成功返回。
双重检测锁dcl
如果a没有使用volatile修饰,就会发生指令重排序可能
if(a==null){
synchronized(DCL.class){
//这两步会发生指令重排
if(a==null){
a=new DCL();
}
}
}
volatile怎么保证有序性
Lock前缀指令实际上相当于一个内存屏障(也成内存栅栏),它确保指令重排序时不会把其后面的指令排到内存屏障之前的位置,
也不会把前面的指令排到内存屏障的后面;即在执行到内存屏障这句指令时,在它前面的操作已经全部完成