为什么Volatile变量不用于原子性

时间:2015-05-25 01:27:06

标签: java multithreading

来自Javadocs

  

使用volatile变量可降低内存一致性的风险   错误,因为对volatile变量的任何写入都会建立一个   在与之后的相关读取之前发生   变量。这意味着始终对volatile变量进行更改   其他线程可见。

当对volatile变量进行的更改始终对任何其他线程可见时,为什么在多个线程写入该变量的情况下不能使用volatile变量。为什么volatile只用于一个线程正在写入或读取的情况,而另一个线程仅读取变量?

如果其他线程始终可以看到更改,则假设线程B想要写入该变量,它将看到新值(由线程A更新)并更新它。当线程A再次想要写入时,它将再次通过线程B看到更新的值并写入它。问题出在哪里?

简而言之,我无法理解这一点。

  

如果两个线程都在读取和写入共享变量,那么   使用volatile关键字是不够的。你需要使用   在这种情况下同步,以保证读写   变量是原子的。

2 个答案:

答案 0 :(得分:5)

volatile有很多用途可以正常使用 - 但也有很多用途。例如,假设您有一个这样的字段:

private volatile int i;

和两个运行++this.i的线程:阅读this.i然后写入它。

问题是++this.i是易失性读取,后跟完全独立的易失性写入。在读取和写入之间可能发生了许多事情;特别是,您可能会遇到两个线程在任一线程写入之前读取i的情况。净效应是i的值仅增加1,即使两个单独的线程都增加了它。

AtomicInteger(以及其他原子)通过允许您在单个原子(≈folatile)步骤中同时读取和写入来解决此类问题。 (它们通过使用比较和交换指令来执行此操作,该指令仅在读取的值仍为当前值时执行写入.increation-and-get方法只运行一个循环,重试此操作直到写入实际成功。 )

答案 1 :(得分:1)

想想“原子性”是什么意思。这意味着在一个线程中发生的两个或多个操作看起来像其他线程可以告诉的原子单元一样。

因此,如果我声明一些volatile int foobar,并且我编写代码来对其执行某些操作,那么编译器如何知道哪些这些操作应该是原子单元?< / p>

当你编写一个synchronized块时,原子单位就是你放在块内的任何东西。