Java的volatile关键字为何不能保证操作的原子性?
- 内容介绍
- 文章标签
- 相关推荐
本文共计1779个文字,预计阅读时间需要8分钟。
问题+在讨论原子性操作时,我们经常会听到一个说法:任意一个volatile变量的读写具有原子性,但volatile++这种操作除外。那么问题就是:为什么volatile++不是原子性的?
答案+因为它不是原子操作。volatile关键字确保了变量的可见性和有序性,但它并不能保证复合操作(如++)的原子性。volatile++涉及到多个步骤:首先读取变量的值,然后进行自增,最后写入新的值。即使每个步骤都是原子的,但整个操作序列并不是原子的,因为它们之间可能被其他线程的读写操作打断。
问题
在讨论原子性操作时,我们经常会听到一个说法:任意单个volatile变量的读写具有原子性,但是volatile++这种操作除外。
所以问题就是:为什么volatile++不是原子性的?
答案
因为它实际上是三个操作组成的一个符合操作。
- 首先获取volatile变量的值
- 将该变量的值加1
- 将该volatile变量的值写会到对应的主存地址
一个很简单的例子:
如果两个线程在volatile读阶段都拿到的是a=1,那么后续在线程对应的CPU核心上进行自增当然都得到的是a=2,最后两个写操作不管怎么保证原子性,结果最终都是a=2。每个操作本身都没啥问题,但是合在一起,从整体上看就是一个线程不安全的操作:发生了两次自增操作,然而最终结果却不是3。
本文共计1779个文字,预计阅读时间需要8分钟。
问题+在讨论原子性操作时,我们经常会听到一个说法:任意一个volatile变量的读写具有原子性,但volatile++这种操作除外。那么问题就是:为什么volatile++不是原子性的?
答案+因为它不是原子操作。volatile关键字确保了变量的可见性和有序性,但它并不能保证复合操作(如++)的原子性。volatile++涉及到多个步骤:首先读取变量的值,然后进行自增,最后写入新的值。即使每个步骤都是原子的,但整个操作序列并不是原子的,因为它们之间可能被其他线程的读写操作打断。
问题
在讨论原子性操作时,我们经常会听到一个说法:任意单个volatile变量的读写具有原子性,但是volatile++这种操作除外。
所以问题就是:为什么volatile++不是原子性的?
答案
因为它实际上是三个操作组成的一个符合操作。
- 首先获取volatile变量的值
- 将该变量的值加1
- 将该volatile变量的值写会到对应的主存地址
一个很简单的例子:
如果两个线程在volatile读阶段都拿到的是a=1,那么后续在线程对应的CPU核心上进行自增当然都得到的是a=2,最后两个写操作不管怎么保证原子性,结果最终都是a=2。每个操作本身都没啥问题,但是合在一起,从整体上看就是一个线程不安全的操作:发生了两次自增操作,然而最终结果却不是3。

