happen-before是什么
happen-before是什么
happen-before出现的原因
为了明确定义多线程场景下重排序的问题,Java引入了JMM(Java Memory Model),也就是Java内存模型。如果有了重排序就会出现原子性,可见性,有序性的问题,但是性能会提升。所以Java内存模型不是真实存在的,而是一套规范,可以方便的使开发者在运行效率和程序开发的方便性之间找到一个平衡点。
一方面要让CPU和编译器可以灵活的进行重排序,另一方面也要告诉开发者,在什么情况下什么样的重排序不需要感知,需要感知什么样的重排序并作出处理。
为了描述这个规范,JMM引入了happen-before,使用happen-before描述两个操作之间的内存可见性。
简单来说,happen-before的意思就是,如果 操作A happen-before 操作B,那么操作A的执行结果必须对操作B可见。
happen-before的七条原则
- 单线程规则:同一个线程中的每个操作都happens-before于出现在其后的任何一个操作。
- 对一个监视器的解锁操作happens-before于每一个后续对同一个监视器的加锁操作。
- 对volatile字段的写入操作happens-before于每一个后续的对同一个volatile字段的读操作。
- Thread.start()的调用操作会happens-before于启动线程里面的操作。
- 一个线程中的所有操作都happens-before于其他线程成功返回在该线程上的join()调用后的所有操作。
- 一个对象构造函数的结束操作happens-before与该对象的finalizer的开始操作。
- 传递性规则:如果A操作happens-before于B操作,而B操作happens-before与C操作,那么A动作happens-before于C操作。
happen-before的传递性
就像七条原则里的第七条,happen-before具有传递性,否则的话岂不是要将所有的可能出现可见性问题的变量都要用volatile修饰。
实例
class A{
private int a = 0;
private volatile int c = 0;
public void set(){
a = 5; //操作1
c = 1; //操作2
}
public int get(){
int d = c; //操作3
return a; //操作4
}
}
上述代码中,由于七条原则中的第一条:单线程规则,所以操作1 happen-before 操作2。由于变量c使用了volatile关键字进行修饰,所以操作2 happen-before 操作3。
所以由于传递性可以推出:操作1 happen-before 操作2 happen-before 操作3 happen-before 操作4
这样一来,操作1结果必须对操作4可见,但是如果没有使用volatile关键字修饰变量c,就不会有这样的关系,那么在先调用set方法后调用get方法时,就可能得不到值