5.6 JMM规范下多线程先行发生原则之happens-before
在JVM中,如果一个操作执行的结果需要对另一个操作可见或者代码重排序,那么这两个操作之间
必须存在happens-before(先行发生)原则,逻辑上的先后关系。
5.6.2 先行并发原则说明
5.6.3 happens-before总原则
5.6.4 happens-before之8条
5.6.5 happens-before总结
5.6.6 案例说明
private int value =0;
public int getValue(){
return value;
}
public int setValue(){
return ++value;
}
问题描述:假设存在线程A和B,线程A先(时间上的先后)调用了setValue()方法,
然后线程B调用了同一个对象的getValue()方法,那么线程B收到的返回值是什么?
答案:不一定
分析happens-before规则(规则5,6,7,8可以忽略,和代码无关)
1 由于两个方法由不同线程调用,不满足一个线程的条件,不满足程序次序规则
2 两个方法都没有用锁,不满足锁定规则
3 变量没有使用volatile修饰,所以不满足volatile变量规则
4 传递规则肯定不满足
综上:无法通过happens-before原则推导出线程A happens-before 线程B,虽然可以确定时间上线程A优于线程B,但就是无法确定线程B获得的结果是什么,所以这段代码不是线程安全的
注意:
如果两个操作的执行次序无法从happens-before原则推导出来,那么就不能保证他们的有序性,
虚拟机可以随意对他们进行重排序
如何修复?
方法一:把getter/setter方法都定义为synchronized方法------->不好,重量锁,并发性下降
private int value =0;
public synchronized int getValue(){
return value;
}
public synchronized int setValue(){
return ++value;
}
方法二:把Value定义为volatile变量,由于setter方法对value的修改不依赖value的原值,满足
volatile关键字使用场景