Volatile关键字为什么不能保证原子性

今天看了C站上看了很多篇关于Volatile保证可见性和有序性但不能保证原子性的文章。大多都是众说纷纭,到最后还是没能够说清楚,这里我说一下自己的理解。

首先明确volatile的特性:

volatile(保证线程可见性,禁止指令重排序)

  • volatile本身就包含了禁止指令重排序的语义

  • 使用volatile关键字会强制将修改的值立即写入主存

以i++为例子:分为三步:读 计算 写

首先主存中有一个变量i = 1。

线程1从主存中读取变量i,并拷贝一份i = 1的副本到自己的高速缓存中。接下来执行i+1操作。自己副本中i = 2。接下来本应该强制将修改的值立即写入主存,但是时间片用完了(时间片用完了就必须停止,这里还没有来得及写入主存),线程1阻塞了。

然后线程2从主存中读取变量i,并拷贝一份i = 1的副本到自己的高速缓存中。接下来执行i+1操作,自己副本中的i = 2。接下来将i = 2写入主存。在写入主存过程中会通过一个总线嗅探机制告诉其它线程的副本i,你失效了。

过一会线程1又分配到了时间片,这个时候应该强制将修改的值立即写入主存,但是去高速缓存中拿值的时候发现自己的副本已经被标记失效了。然后就得重新去主存中拿i值。重新到主存中拿到的值i = 2。最后把i = 2写入主存。(读和计算的操作是已经执行过了的命令,所以它不会重新计算了,它只差写操作的命令)

本来是两个线程,分别对i执行+1操作,正确值应该为3,但是最终为2,显然是有问题的。

所以volatile只能保证变量的可见性,不能保证原子性。

扫描二维码关注公众号,回复: 14609376 查看本文章

i++是三个原子操作组合而成的复合操作。它本身就不是原子操作,不能依靠volatile这个保证可见性和有序性的关键字来保证原子性。

猜你喜欢

转载自blog.csdn.net/m0_57545353/article/details/126389584