Java volatile参考与AtomicReference
如果我只使用Java volatile参考与AtomicReference,java,concurrency,Java,Concurrency,如果我只使用get()和set(),那么volatile对象引用和AtomicReference中的get()和set()方法之间有什么区别吗?简短的回答是:没有 从软件包文档中。引述: 原子访问和更新的记忆效应通常遵循挥发物的规则: get具有读取volatile变量的记忆效果 set具有写入(分配)一个volatile变量的记忆效果 顺便说一句,文档非常好,所有内容都解释过了 是一个较新的(Java 6+)操作,其语义无法通过volatile变量实现。有关更多信息,请参阅。不,没有 A
get()
和set()
,那么volatile
对象引用和AtomicReference
中的get()和set()
方法之间有什么区别吗?简短的回答是:没有
从软件包文档中。引述:
原子访问和更新的记忆效应通常遵循挥发物的规则:
get
具有读取volatile
变量的记忆效果
set
具有写入(分配)一个volatile
变量的记忆效果
顺便说一句,文档非常好,所有内容都解释过了
是一个较新的(Java 6+)操作,其语义无法通过volatile
变量实现。有关更多信息,请参阅。不,没有
AtomicReference提供的额外功能是compareAndSet()方法和friends。如果您不需要这些方法,volatile引用将提供与AtomicReference.set()和.get()相同的语义。提供普通volatile变量不提供的附加功能。正如您已经阅读了API Javadoc一样,您将知道这一点,但它也提供了一个锁,它对某些操作非常有用
但是,除非您需要此附加功能,否则我建议您使用普通的volatile
字段。是解决此类困惑的最佳方法之一。如果查看AtomicReference中的代码,它使用volatie变量来存储对象
private volatile V value;
所以,很明显,如果您要在AtomicReference上使用get()和set(),这就像使用易失性变量一样。但正如其他读者所评论的,AtomicReference提供了额外的CAS语义。因此,首先确定是否需要CAS语义,如果只需要,则使用AtomicReference。有几个区别和权衡:
使用AtomicReference
get/set具有与volatile字段相同的JMM语义(如javadoc所述),但是AtomicReference
是引用的包装,因此对该字段的任何访问都涉及进一步的指针追踪
内存占用将成倍增加(假设采用压缩的OOPs环境,这对大多数虚拟机都适用):
- 挥发性ref=4b
AtomicReference
=4b+16b(12b对象头+4b参考字段)
AtomicReference
提供了比volatile引用更丰富的API。您可以通过使用AtomicFieldUpdater
或使用Java 9 aVarHandle
重新获得volatile引用的API。如果你喜欢用剪刀跑步,你也可以直达sun.misc.Unsafe
<代码>原子引用
本身是使用不安全
实现的
那么,什么时候最好选择一个而不是另一个:
- 只需要获得/设置?坚持使用易失性字段、最简单的解决方案和最低的开销
- 需要额外的功能吗?如果这是代码中对性能(速度/内存开销)敏感的部分,请在
/AtomicReference
/AtomicFieldUpdater
之间做出选择,您往往会为性能提升付出可读性和风险。如果这不是一个敏感区域,只需选择不安全
。库编写器通常会根据目标JDK、预期的API限制、内存限制等情况混合使用这些方法AtomicReference
私有易失性状态;
...
公共设置新闻状态(状态新闻状态){
状态=新闻状态;
}
公共无效dosomething条件(){
if(status.isOk()){
System.out.println(“Status is ok:+Status);//此处的Status可能不再是ok,因为在此期间,一些名为setNewStatus()。setNewStatus应该同步
}
}
带有AtomicReference的实现将免费为您提供一个写时同步拷贝
私有原子引用状态包装器;
...
公共无效dosomething条件(){
Status Status=statusWrapper.get();
if(status.isOk()){
System.out.println(“Status is ok:+Status);//这里即使同时有人调用setNewStatus(),我们仍然引用旧的
}
}
有人可能会说,如果您替换了以下内容,您仍然可以拥有一份合适的副本:
Status Status=statusWrapper.get();
与:
Status statusCopy=状态;
然而,第二个更可能在将来的“代码清理”过程中被某人意外删除。并且同意更长的答案。我们至少需要一个链接。链接到更长的答案:那么,区别就在于它们的性能。如果没有区别,你就不会建议使用一个而不是另一个。性能基本相同。原子引用增加了复杂性和内存使用。@BT A
volatile
字段可以像任何常规字段一样使用,而访问AtomicReference
中的值需要通过get
和set
方法。“JDK源代码是解决此类困惑的最佳方法之一。”=>我不一定同意——javadoc(类的契约)是最好的方式。代码中的内容回答了特定实现的问题,但代码可以更改。例如,hashmap在JDK 6中是不稳定的,但在Java 7中不再是不稳定的。如果您的代码是基于变量是易变的这一事实,那么在升级JDK时它可能会崩溃。。。诚然,这个例子是不同的,但你明白了。这是标准缩写吗?比较和交换=)