volatile
Object引用之间是否有任何区别AtomicReference
,如果我只使用get()
和set()
-methods AtomicReference
?
简短的回答是:不.
从java.util.concurrent.atomic包doc:
访问和更新原子的记忆效应通常遵循挥发物的规则:
get
具有读取volatile
变量的记忆效应.
set
具有写入(赋值)volatile
变量的记忆效应.
顺便说一句,包的文档非常好,一切都解释了......
lazySet
(在Java 6中引入)是一个引入的新操作,它具有通过volatile
变量无法实现的语义; 有关更多信息,请参阅此帖子.
不,那里没有.
AtomicReference提供的额外功能是compareAndSet()方法和朋友.如果您不需要这些方法,则volatile引用提供与AtomicReference.set()和.get()相同的语义.
有几个不同之处和权衡:
使用AtomicReference
get/set具有与volatile字段相同的JMM语义(如javadoc状态),但它AtomicReference
是引用的包装器,因此对字段的任何访问都涉及进一步的指针追踪.
的内存占用乘以(假设压缩糟糕的环境,这是真实的大多数虚拟机):
volatile ref = 4b
AtomicReference
= 4b + 16b(12b对象标题+ 4b ref字段)
AtomicReference
提供比易失性参考更丰富的API.您可以使用AtomicFieldUpdater
或使用Java 9 a 重新获得易失性引用的API VarHandle
.sun.misc.Unsafe
如果你喜欢用剪刀跑步,你也可以直达.AtomicReference
本身是使用Unsafe
.
那么,什么时候选择一个比另一个好:
只需要获取/设置?坚持不稳定的领域,最简单的解决方案和最低的开销.
需要额外的功能吗?如果这是性能(速度/内存开销),则代码的敏感部分会在AtomicReference
/ AtomicFieldUpdater
/ Unsafe
您倾向于支付可读性的位置和性能增益风险之间做出选择.如果这不是一个敏感区域,那就去吧AtomicReference
.库编写者通常使用这些方法的混合,具体取决于目标JDK,预期的API限制,内存约束等.
JDK源代码是回答这种混淆的最佳方法之一.如果查看AtomicReference中的代码,它会使用一个volatie变量进行对象存储.
private volatile V value;
因此,显然如果您要在AtomicReference上使用get()和set(),就像使用volatile变量一样.但正如其他读者所评论的那样,AtomicReference提供了额外的CAS语义.因此,首先要确定是否需要CAS语义,如果只是,那么请使用AtomicReference.