浅析volatile

关于 volatile  我这里要好好总结一下。

volatile关键字 对一个变量修饰,起到了两个作用,立即可见和禁止指令重排序。

本质上 都是在该变量被赋值后  多了一条指令 lock addl $0x0,(%esp)  这个指令起了两个作用。


首先说立刻可见:

一个是带lock前缀的addl汇编指令,作用是本cpu的cache 立刻写入主内存(这里是把当前修改变量的虚拟机栈的内存模型认为是cpu寄存器和高速缓存这个模型来讲的,因为虚拟机和硬件系统本身的优化, 会让工作内存优先存储在寄存器和高速缓存中。),从而引起别的cpu无效化自身的cache。

正常来说线程间访问变量  应该都是通过主内存的,访问的变量是有缓存的,并不是每次都从主内存读的,只有当在工作内存对赋值进行赋值后,写入主内存,才会引起其他cpu内核的cache无效,而工作内存中该变量被修改(use和assign指令)以及从工作内存写入主内存是有延迟的(即store和write指令),所以在这个空档期,另一给线程一条读取该变量的指令被其他内核所执行, 导致读到了脏数据。

而这条指令的关键就在于, 对该变量赋值后,立刻对该变量进行store和write指令(具有原子性) 强制其他内核从主内存来访问数据。 这条指令的执行意味着 变量已经同步到主内存中了。这样就不会产生脏读。

禁止指令重排序:

指令重排是值cpu允许多条指令不按程序规定的顺序,分开给不同的电路单元处理,那么lock addl 这条指令就是一条内存屏障指令(具体内存屏障指令因处理器架构而异)。表明在一个方法内执行的代码所对应的汇编指令不允许重排序。

volatile  不适用的场景:

运算结果依赖变量的当前值。 有其他状态变量共同参与不变约束。

仅通过字节码指令的分析:

getstatic 把race 值取到 操作栈顶。也就是工作内存或者 cache中。这时候取到的是正确的值。
当把累加后的结果 进行赋值的时候, 能保证赋值操作 和 将值写回到主内存的之间过程内,不会插入访问指令。
但是add 操作的时候,而 这个原值 就已经是过期数据了 。
可以这样理解。几个线程 cache中同时存在着 i=1的值。然后同时进行累加。累加的过程不分先后,是并行执行。所以每个线程 都累加 到了2 。 这样肯定不是正确的结果。

所以 volatile 仅仅是做到了立即可见和防止指令重排序,而并非是并发安全。







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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值