Java易失性参考与AtomicReference

如果我只是使用AtomicReference中的get()set()方法,那么在volatile对象引用和AtomicReference之间是否有区别?

简短的回答是:没有。

从java.util.concurrent.atomic包doc :

对于访问和更新primefaces的记忆效应一般遵循挥发物的规则:

  • get读取volatilevariables的记忆效应。
  • set具有写入(分配) volatilevariables的记忆效应。

顺便说一下,该软件包的文档是非常好的,一切都被解释…


lazySet (在Java 6中引入)是一个较新的操作,引入了通过volatilevariables无法实现的语义; 看到这个职位了解更多信息。

不,那里没有。

AtomicReference提供的额外function是compareAndSet()方法和朋友。 如果不需要这些方法,那么volatile引用提供与AtomicReference.set()和.get()相同的语义。

JDK源代码是解决这种混乱的最好方法之一。 如果你看AtomicReference中的代码,它使用volatilevariables来存储对象。

 private volatile V value; 

所以,显然如果你打算在AtomicReference上使用get()和set(),就像使用一个volatilevariables。 但是正如其他读者所评论的,AtomicReference提供了额外的CAS语义。 所以,首先要确定是否需要CAS语义,如果你只使用AtomicReference。

AtomicReference提供了一个普通的volatilevariables不提供的附加function。 正如你已经读过API,你将会知道这一点,但是它也提供了一个对某些操作有用的锁。

但是,除非你需要这个额外的function,否则我build议你使用一个普通的volatile字段。

有几个差异和折衷:

  1. 使用AtomicReference获取/设置与易失性字段具有相同的JMM语义 (如javdoc状态),但AtomicReference是引用的包装,所以对该字段的任何访问都涉及到进一步的指针追踪

  2. 内存占用是相乘的 (假设压缩的OOPs环境,对于大多数虚拟机是这样的):

    • 挥发性ref = 4b
    • AtomicReference = 4b + 16b(12b object header + 4b ref field)
  3. AtomicReference提供了比volatile参考更丰富的API。 您可以通过使用AtomicFieldUpdater或Java 9的VarHandle来重新获得volatile参考的API。 如果你喜欢用剪刀跑步,你也可以直接到sun.misc.UnsafeAtomicReference本身是使用Unsafe实现的。

那么,什么时候select一个好呢?

  • 只需要获得/设置? 坚持一个易变的领域,最简单的解决scheme和最低的开销。
  • 需要额外的function? 如果这是性能(速度/内存开销),那么您的代码的敏感部分可以在AtomicReference / AtomicFieldUpdater / Unsafe之间进行select,而您往往需要支付可读性和风险,以获得性能提升。 如果这不是一个敏感的领域只是去AtomicReference 。 库编写器通常使用这些方法的混合,具体取决于目标JDK,期望的API限制,内存限制等。