为什么volatile修饰的i++是线程不安全的?

volatile可以保证可见性,那么多线程情况下,线程们也总是可以从主存中拿到最新的值,那为什么还是线程不安全?哪里出了问题?

我再把问题细化一下:首先i++不是原子操作。他分成三个部分,我简称其为S1,S2,S3。
S1:线程将i的值从主存中加载至cache
S2:CPU从cache中获取i的值并计算
S3:线程将计算好的i的值从cache写入主存

那么在没有添加volatile时,显然i++是不安全的。例如线程T1,T2,分将i从0加到1准备写入主存的时候,可能T1线程先写入了,但是T2线程不知道,也写入了,会造成写覆盖,所以线程不安全。

但是加了volatile之后,情况会有些许变化。volatile保证可见性,意味着,在上边的例子中,当T1成功写入的时候,由于缓存一致性协议,T2会立刻知道主存已经被修改,同时自己的缓存已经失效。所以T2会从主存中重新加载更新后的数据。那么既然T2已经拿到新的数据了,于是T2去重新执行i++,照此来说,就应该是线程安全的了。请问哪里出了问题?
#Java开发##学习路径#
全部评论
在多线程的情况下,一个线程修改了i的值,由于缓存一致性协议,其他的线程获取的i的值会失效。但是,可能会出现这么一种情况。在这个线程修改i的值的同时,其他线程已经把i从缓存行中加载到了cpu寄存器,缓存一致性协议只对缓存行有效,对寄存器不起作用。所以会继续执行i++的操作。最后导致线程安全问题。
2 回复
分享
发布于 2021-07-28 13:50
volatile只是保证每次要取i的值的时候从内存中取,如果取之后改之前被其它线程改了,这种情况也没法发现啊。
1 回复
分享
发布于 2021-07-26 08:18
阅文集团
校招火热招聘中
官网直投
i++不是原子操作,volatile不保证原子性
点赞 回复
分享
发布于 2021-07-26 08:15
一楼正解,volatile只能保证变量在内存的可见性。i++反编译成字节码文件后会发现它是多条指令实现其功能,如果这时候有其它线程对其进行读取访问,可能会导致最终读取或写入的值不是你想要的结果,从而引发线程安全问题。
点赞 回复
分享
发布于 2021-07-26 08:39

相关推荐

点赞 3 评论
分享
牛客网
牛客企业服务