volatile是怎么保证可见性和防止指令重排序的

volatile怎么保证可见性

每个线程操作数据的时候会把数据从主内存读取到自己的工作内存,根据MESI思想,如果某个线程修改数据写回到主内存,其他线程能通过嗅探检查到本地数据无效,然后重新从主内存读取到自己的工作内存。

volatile怎么防止指令重排序

通过在指令间加入内存屏障来防止指令重排序。

基本概念

MESI

Modified(修改)、Exclusive(独占)、Share(共享)、Invalid(无效)

  1. CPU1使用共享数据时会先将数据拷贝到CPU1缓存中,然后置为独占状态(E),这时CPU2也使用了共享数据也会拷贝到CPU2缓存置为独占状态(E)。
  2. 通过总线嗅探机制,当该CPU1监听总线中其他CPU对内存进行操作,此时共享变量在CPU1和CPU2两个缓存中的状态会被标记为共享状态(S)。
  3. 若CPU1将变量通过缓存回写到主存中,需要先锁住缓存行,此时状态切换为修改状态(M),并向总线发消息告诉其他在嗅探的CPU该变量已经被CPU1改变并回写到主存中。
  4. 接收到消息的其他CPU会将变量从共享状态(S)改成无效状态(I),缓存行失效。若其他CPU需要再次操作共享变量则需要重新从内存读取。

实际状态的扭转过程是:独占→共享→修改→无效

嗅探

每个处理器通过嗅探在总线上传播的数据来检查自己的缓存数据是不是过期了,当处理器发现自己缓存数据对应的内存地址被修改,就会将当前处理器的缓存数据设置成无效状态,当处理器对这个数据进行修改操作的时候,会重新从系统内存中把数据读到处理器缓存里。

总线风暴

在java中使用unsafe实现CAS,而其底层由C++调用汇编指令实现的,如果是多核cpu是使用lock cmpxchg指令,单核cpu使用compxch指令。

如果在短时间内产生大量的CAS操作再加上volatile的嗅探机制则会不断地占用总线带宽,导致总线流量激增,就会产生总线风暴。

happens-before

从JDK1.5开始,提出了happens-before的概念,如果一个操作执行的结果需要对另一个操作可见,那么这两个操作之间必须存在happens-before关系。

注意点

1.volatile只能保证可见性,不能保证原子性。但用volatile修饰long和double可以保证其操作原子性。

2.volatile属性的读写操作都是无锁的。

3.内存屏障

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值