一个关于Java volatile关键字可见性和原子性的问题

一个变量arg用volatile修饰后,会直接保存在主存中
有两个线程A和B访问它

A和B同时将arg读取到了工作内存
若A对arg进行修改后,会导致B工作内存中的arg缓存无效
所以线程B需要再次从主存中读取arg
这就保证了线程B读取的是arg的最新值

问题:
线程A和线程B都对arg变量进行++操作

++操作的过程为,先读取arg,对arg加1,然后写回主存

假设:
arg初始值为0
线程A读取了arg,阻塞
线程B读取arg,对其++,并写回主存,此时arg=1
根据可见性,线程A工作内存中的arg变量应该会失效
此时线程A需要重新从主存中读取arg=1,然后进行++操作,将结果2写回内存

然而:
看了一些博客,都没有涉及到加粗文字的步骤。

https://img.mukewang.com/5cbfcf2b000187f308000156.jpg

按照这样的说法,arg会被写两次,每次都是1。
线程A读取arg放入工作内存后,线程B的写操作不会影响线程A工作内存中arg变量的缓存。

问:这时候可见性不发挥作用么?


偶然的你
浏览 447回答 4
4回答

萧十郎

volatile保证你每次读取都能读到最新的值,可是并不会更新你已经读了的值,它也无法更新你已经读了的值。

青春有我

没有什么工作内存、主内存,对编译器来说内存和Cache的区别是不可见的,编译器关心的是内存和寄存器,如果你非要把寄存器叫做工作内存也不是不可以但是很别扭……volatile影响的是编译器在连续的多个语句之间是否可以假设这个变量没有被别人修改,这样就可以继续用之前在寄存器里面的值。否则编译器总是去内存里读一个新的值出来,而不使用寄存器里面暂存的值。它也不关心这其中有没有别人实际修改了这个值。至于多核系统内存和Cache之间的关系,在x86架构上这是CPU自己会处理的问题,在一些别的架构上可能会设计一些特殊的指令。也就是说根本就没有你说的一个修改导致另一个失效那样子的魔法过程。如果另一个线程是在++的执行过程中,刚读出来的值被修改了,它当然是没有办法用超能力去预知这个事情然后重新读一次的。

慕斯王

首先,使用volatile,工作内存的概念依然存在,只是会通过读写屏障来达到直接读写内存的效果。所以,你可以认为:volatile变量直接操作内存(虽然严格说并不是)。读值是指读到cpu,后cpu对值++,然后重新写回内存(或工作内存),读到的值指的是读到CPU的值,这个是没法因为内存值的改变而自动改变的。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java