Java易失性参考与AtomicReference
如果我只是使用AtomicReference
中的get()
和set()
方法,那么在volatile
对象引用和AtomicReference
之间是否有区别?
简短的回答是:没有。
从java.util.concurrent.atomic包doc :
对于访问和更新primefaces的记忆效应一般遵循挥发物的规则:
get
读取volatile
variables的记忆效应。set
具有写入(分配)volatile
variables的记忆效应。
顺便说一下,该软件包的文档是非常好的,一切都被解释…
lazySet
(在Java 6中引入)是一个较新的操作,引入了通过volatile
variables无法实现的语义; 看到这个职位了解更多信息。
不,那里没有。
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字段。
有几个差异和折衷:
-
使用
AtomicReference
获取/设置与易失性字段具有相同的JMM语义 (如javdoc状态),但AtomicReference
是引用的包装,所以对该字段的任何访问都涉及到进一步的指针追踪 。 -
内存占用是相乘的 (假设压缩的OOPs环境,对于大多数虚拟机是这样的):
- 挥发性ref = 4b
-
AtomicReference
= 4b + 16b(12b object header + 4b ref field)
-
AtomicReference
提供了比volatile参考更丰富的API。 您可以通过使用AtomicFieldUpdater
或Java 9的VarHandle
来重新获得volatile参考的API。 如果你喜欢用剪刀跑步,你也可以直接到sun.misc.Unsafe
。AtomicReference
本身是使用Unsafe
实现的。
那么,什么时候select一个好呢?
- 只需要获得/设置? 坚持一个易变的领域,最简单的解决scheme和最低的开销。
- 需要额外的function? 如果这是性能(速度/内存开销),那么您的代码的敏感部分可以在
AtomicReference
/AtomicFieldUpdater
/Unsafe
之间进行select,而您往往需要支付可读性和风险,以获得性能提升。 如果这不是一个敏感的领域只是去AtomicReference
。 库编写器通常使用这些方法的混合,具体取决于目标JDK,期望的API限制,内存限制等。