volatile :保证共享变量的可见性


如何保证可见性: 加入该关键字,编译时多了一个lock的汇编指令

可见性到底是什么?线程a修改了共享变量i,线程b不能及时拿到最新的值,导致数据不一致。
原因:
    硬件层面:cpu,内存,i/o 的处理速度差别是很大的,所以会使用一些其他技术。
      1.cpu增加高速缓存:L1,L2,L3。L1,L2是cpu私有的缓存。L1又分为指令缓存和数据缓存,cpu还有寄存器。L3是多个核心共享的缓存。
      2.引入线程、进程概念利用cpu过剩资源
      3.指令优化(重排序)。

   JMM层面:

缓存的出现导致了数据不一致。

cpu的解决方案:

1.加入总线锁,但是会有性能问题,所以引入了缓存锁,降低锁的控制粒度。

2.加入缓存锁,引入缓存一致性协议。达到缓存数据的一致性,不同的cpu架构,协议是不一样的。x86是mesi协议:多个核心具有通信协议,相互监听,M-E-S-I 四种状态会相互转化

此时cpu0和cpu1和主内存的值是一致的,都是出于Share状态。

当有线程把cpu0的数据改为2时,会告诉其他cpu将数据该为Invalid状态,cpu0状态由Share变为Modify,同时cpu1的缓存行数据变为Invalid状态(当cpu1需要使用数据的时候就不会从缓存行拿值而是从主内存获取最新的值)。当cpu状态为MES是都可以被读取,只有 I 状态的cpu会从主内存读取。处于ME状态的cpu是可以写的, S状态的cpu需要把其他cpu的状态设置为 I 无效,才可以写。

Modify-->Exclusive  状态的改变:当cpu0被修改后,其他cpu置为无效,此时cpu0为M,当其他cpu的缓存行没有缓存的时候,即不在有缓存数据的时候(由Invalid直接删除了)cpu0就变为了E独占状态。

基于MESI协议(CPU硬件层面的实现)可以解决缓存一致性问题,但是并没有解决可见性问题。

 

所以cpu引入了storebuffer。即当cpu0在修改值的时候,不直接去修改,而是把修改指令放到storebuffer,storebuffer把指令同步到缓存行,缓存行再同步到主内存。当cpu把指令放到storebuffer后,就认为执行成功了,不再阻塞。

不过,仍然会存在可见性问题:storebuffer中有修改指令了,但是没有及时同步到缓存行和主内存。

上面的情况cpu引入storebuffer后导致了异步乱序执行,进一步导致了重排序,进一步导致了可见性问题。

最终cpu无论如何优化,都无法从硬件层面解决可见性问题。

所以出现了从指令方面的解决方案:cpu指令->内存屏障->解决了可见性问题。

cpu层面提供了三种屏障:

写屏障,读屏障,全屏障。storebarrier ,loadbarrier ,fullbarrier

jvm-> valatile->lock(缓存锁)->内存屏障-> 解决可见性

内存屏障,重排序和平台以及硬件有关系。但是java是一次编译随处运行的,所以在java中引入了JMM的抽象内存模型。


      
  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值