引用赋值是原子的,为什么要使用AtomicReference

时间:2013-03-04 07:12:31

标签: java multithreading concurrency

我对AtomicReference有一个简单的一般性问题。

为什么使用AtomicReference,如果引用赋值在java中是原子的?

另外,我想问一下64位虚拟机中的引用分配是否是原子的?

我们是否需要volatile才能将参考分配原子化?

3 个答案:

答案 0 :(得分:24)

  

为什么使用AtomicReference,如果引用赋值在java中是原子的?

当新值的创建所依据的决定取决于引用的先前值时,您需要它。例如,当实现某些LinkedList之类的数据结构时,您不想将头部设置为引用前一个节点的新节点。在读取前一个节点和将头设置为新节点之间的时间内,某个其他线程可以同时更新头参考值。如果我们的线程不会意识到这种变化,它就会丢失。

  

我们是否需要volatile才能将参考分配原子化?

操作本身将在执行它的CPU内核上执行原子操作,但不能保证其他内核上的线程在下次读取时会知道它。

答案 1 :(得分:21)

我之前的回答是不正确的,正如juancn的评论所解释的那样:

  

这是Atomic*类和易失性访问之间的区别。参考分配只是在没有发生单词撕裂的意义上是原子的,但是没有可见性或重新排序保证。 Java保证在所有基本类型和引用的限制意义上的原子写入,但不保证long / double(尽管在64位VM中我认为它们总是原子的)。

上一个回答

主要适用于compareAndSetgetAndSet方法。否则你不能原子地做这个(需要2个操作)。

答案 2 :(得分:5)

原因是即使引用是原子的,它在非常狭窄的意义上也是原子的。

如果一个线程写了一个非易失性引用,那么保证的是其他线程将看到整个写入或根本看不到它(没有单词撕裂/垃圾)。

但绝不保证任何其他线程都能看到它,也不会保证它们会以相同的顺序出现。

AtomicReference提供了更强大的保证(除了CAS操作),基本上它们的行为类似于volatile:

  • 在线程B中发生的任何写入在易失性写入之前在线程B中在后续易失性读取该变量之后可见
  • 易失性操作无法重新排序