volatile

2020年五一的倒数第二天假了,其实还是那个想法,如果是个穷人,其实假期对于自己来说,只是一个追赶别人的一个机会。废话不多说,今天聊一下并发编程中的valatile。


volatile,是什么,它是修饰变量的,修饰完了之后有什么变化呢?

两点:1,让该变量在多个线程之间保持可见性  2,在jvm层次可以设置内存屏障防止重排序的事情发生


什么是线程的可见性?或者说什么是线程的不可见性?

不管单核的还是双核的cpu其实都有着自己的缓存,例如上图,在对A变量进行计算动作的时候,cpu会先把A加载到自己的缓存空间之中(这里有cpu的一级,二级,三级的缓存之说,我们就统一叫缓存),然后通过对缓存中的A进行计算,动作完成之后再刷新到内存之中(严格意义上讲应该叫做主存当中),这里便于理解就叫内存,这样就会有一个问题,如果cpu1把A的值修改了,但是cpu2 读的还是之前它自己缓存的A,那么就不对了,这就是线程的不可见问题,那么怎么办?加了volatile之后,如果cpu1 修改了A的值,它会通知cpu2 该变量也就是该缓存行失效了,你再读的时候需要去主存里面读,而不是读自己的缓存。

这就是volatile保持可见性的原因。

听到这里,肯定是又有些不明白,怎么 通知的,为什么可以通知?


要说明上面的两个问题,不得不说一下缓存行,与缓存一致性的概率、

首先什么叫做缓存行?

cpu读取的时候,是通过一行或者说一块来读的,你可以理解为读取的时候是需要用一个数组来读的,而这个数组有一个长度,这么设计是考虑到,大多数相邻的变量一起使用的概率要大一些,所以如果可以一起读到缓存当中,下次取相邻的变量的时候可以直接去自己缓存中拿,提高效率。这样有一个问题呀?那么这个缓存行该定义多大呢? 在64位操作系统中,这个缓存行是64个字节。

64这个数字是怎么来的? 思考一个问题,如果缓存行的容量是1,那么每次读取的速度是非常快的,但是局部利用率是0; 如果缓存行的容量是10000,那么每次读取的速度是很慢的,但是局部利用率是很大的,所以64是综合考虑取得一个折中值。

 缓存行,了解了,那么什么是缓存一致性,就是两个cpu都加载了自己的缓存行,刚好两个缓存行都包含一个A变量,那么如果cpu1改变了这个A的值,它自动通知cpu2 让它不要读自己的缓存中的A,去主存中刷新这个A的值,这就是缓存一致性。我们常说的mesi其实只是实现了缓存一致性的一种方式。


可见性的问题是搞清楚了,但是内存屏障和防止重排序是什么呢?

依旧先了解一个常识,就是cpu并不是每次都按照我们写的代码一行一行的,下面一行一定要等到上面一行执行为完毕,才会执行。例如:

x=a;

y=1;

上面这两行代码,如果x=a,比y=1要耗时长,然后他们两个之间也没有相互关系,我是不需要等到x=a执行完了之后才去执行y=1的。或者说我也可以先执行y=1;这个赋值操作。

再例如:

class Object{

        c=1;

}

Object o = new Object();

在new的时候,大体有四个动作:1,申请一块内存空间; 2,初始化C设置初始值0 ;3,初始化C设置真实值为1 ;4,将o指向c

其实3和4就可以倒过顺序来执行,这就是cpu的乱序执行,指令的重排序问题。其实它的目的是为了提高cpu的执行效率。

as-if-serial : 看起来是序列化的,说的就是不管cpu如果进行指令的重排序,最后一个线程从上往下执行的最后结果是不变的。

happens-before: 说的是 在jvm层次上,如果要进行重排序需要遵循的规则。load store随机组合的内存屏障实现。

阻止重排序能解决什么问题:最典型的就是DCL(double check lock)模式下的单例,安全问题,只有加了volatile才能保证该单例任何时候才是完整的,这里就不展开说了,上面其实已经自己讲过了 new的四个动作。也是问题的关键所在。


最后说一下,虽然volatile解决了可见性和有序性,但是它并未解决原子性的问题。原子性怎么解决?那就去上一篇synchronize的文章。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值