先说一下概念:
-
可见性:
一个线程对共享变量的修改,另外一个线程能够立刻感知到,我们称为可见性; -
原子性:
一个或者多个操作在 CPU 执行的过程中不被中断的特性称为原子性; -
有序性:
指令重排导致顺序被打乱;
线程工作内存: 是指 Cpu 的 ‘寄存器’ 和 ‘高速缓存’,线程的 working memory 是cpu的寄存器和高速缓存的抽象描述,数据读取顺序优先级 是:寄存器->高速缓存->内存
可见性:
线程工作空间导致可见性问题
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hNCfYp7P-1570757836145)(https://github.com/lantaoGitHub/photos/blob/master/Concurrency/%E5%85%B1%E4%BA%AB%E5%8F%98%E9%87%8F%E5%8F%AF%E8%A7%81%E6%80%A7.png?raw=true)]
例如:线程A在主存中年将变量one=0拉去到自己的工作内存中,然后做了one = 5,当然这个操作是在cpu的寄存器中进行的,然后写会高速缓存中,这时线程A的高速缓存还未执行同步主内存的操作,线程B又将one=0从主存拉取到了线程B的工作内存中,导致A线程已经更新但是B线程看不到的可见性问题;
原子性:
线程切换导致原子性问题 ++count
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1NoRLBJh-1570757836147)(https://github.com/lantaoGitHub/photos/blob/master/Concurrency/%E7%BA%BF%E7%A8%8B%E5%88%87%E6%8D%A2%E5%AF%BC%E8%87%B4%E5%8E%9F%E5%AD%90%E6%80%A7%E9%97%AE%E9%A2%98++count%20.png?raw=true)]
例如:当线程A从主内存中将共享变量Count加载到线程A的工作内存后,发生了线程切换,这个时候线程B也将共享变量Count从主内存加载到了线程B的工作内存,这时线程A和B的工作内存中count都是0,线程B执行了Count = Count + 1,然后写回到主内存,这时候线程切换完成,回到了线程A再次执行 Count = Count + 1,再将线程A工作内存计算过的count写回主内存,现在我们得到的主内存呢中Count值是1而不是2。
有序性:
指令重排导致有序性问题;
在这里讲一个例子,就是获取单例双重检查锁(double-checked locking)判断:
/**
* @Auther: lantao
* @Date: 2019-03-28 14:32
* @Company: 随行付支付有限公司
* @maill: lan_tao@suixingpay.com
* @Description: TODO
*/
public class Test1 {
private DoMain doMain;
public DoMain getDoMain(){
if(doMain == null){
synchronized (this.getClass()){
if(doMain == null){
doMain = new DoMain("");
}
return doMain;
}
}else{
return doMain;
}
}
}
在上边的代码中在synchronized内和外都有一个if判断,判断doMain是否为null操作,有很多人对synchronized中的if null判断不理解,其实可以这样想,线程A和线程B都执行到了synchronized这里进行竞争锁,结果A得到锁,判断if null,结果还未实例化,继续进行实例化,然后return对象并释放锁,这时线程B获取到了锁进入if null判断,发现doMain已经被线程A实例化过了,直接返回实例即可,第二个if null的作用就在这里;
看上去上边的代码是完美的,但是new的操作上我们理解是:
- 创建内存M
- 在内存M上初始化doMain对象
- 将内存M的地址指向变量doMain
但是实际上优化后(指令重排)的执行路径可能是这样的:
- 创建内存M
- 将内存M的地址指向变量doMain
- 将内存M的地址指向变量doMain
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W4Phn3Ou-1570757836147)(https://github.com/lantaoGitHub/photos/blob/master/Concurrency/%E6%9C%89%E5%BA%8F%E6%80%A7%E9%97%AE%E9%A2%98.png?raw=true)]
上图大家应该都看的明白,我就不写了,本文主要就是让作者加深印象,本文是参考:https://time.geekbang.org/column/article/83682 总结的