可能重复:
Java: volatile boolean vs AtomicBoolean在原子变量中使用volatile变量与变量之间有什么区别?
当它适合使用volatile
原语(例如boolean
,integer
或long
)代替AtomicBoolean
,AtomicInteger
或AtomicLong
,反之亦然?
可能重复:
Java: volatile boolean vs AtomicBoolean在原子变量中使用volatile变量与变量之间有什么区别?
当它适合使用volatile
原语(例如boolean
,integer
或long
)代替AtomicBoolean
,AtomicInteger
或AtomicLong
,反之亦然?
可见性语义完全相同,使用原子基元的情况非常有用,当您需要使用它们的原子方法时。
例如:
if (volatileBoolean) {
volatileBoolean = !volatileBoolean;
}
可在多线程环境作为变量可以在两条线之间改变创建的问题。如果你需要测试&分配是原子,你可以使用:
atomicBoolean.compareAndSet(true, false);
'volatileBoolean =!volatileBoolean;'本身可能存在线程问题。 –
@PeterLawrey好点。 – assylias
因为否定布尔值是一个两步操作? –
使用纯挥发性更简单,更有效的,如果你想要做的是设置或获取价值。 (但没有得到&设置值)
如果你想要更多的操作,如getAndIncrement或compareAndSwap你需要使用AtomicXxxx类。
感谢您的回答 –
lazySet on atomic通常会赢得不稳定的'写入'(特别是TSO体系结构),但它具有不同的语义。 – bestsss
lazySet速度更快,因为它不会停止CPU管道。 –
我们已经开始禁止在我们的资源中使用volatile
,因为编写代码并不总是按预期工作。
根据我的经验,人们在线程之间添加volatile来共享一个值。然后,别人开始修改价值。大多数情况下,这是有效的。但在制作过程中,你会发现很难追查的奇怪错误。计数器增加100'000次(测试只增加10次),但最终为99'997。在Java 1.4中,很长时间的值可能会被破坏,真的很少。
另一方面,Atomic*
帮助类仅施加很小的开销,并且它们始终按广告方式工作。
所以,除非你有很好的理由(*)使用volatile
,否则总是更喜欢Atomic*
助手类。
如果您不确切知道Atomic*
辅助类中的每个字符的含义,那么您应该避免使用volatile
。
*:不成熟的优化从来就不是一个好的理由。
感谢您的回答 –
*“编写代码并不总是按预期方式工作,非常容易。”* =>您可以更具体吗?例如,你是否认为人们假设volatile会给出原子性保证? – assylias
@assylias:我在我的答案中添加了一些例子。 –
Atomic*
类包装相同类型的volatile
原语。来源:
public class AtomicLong extends Number implements java.io.Serializable {
...
private volatile long value;
...
public final long get() {
return value;
}
...
public final void set(long newValue) {
value = newValue;
}
所以。
何时适合使用易失性基元(例如,布尔,整数或长)代替的AtomicBoolean,或的AtomicInteger的AtomicLong
如果你正在做的是获取和设置Atomic*
,那么你可能也只是有一个volatile
场来代替。
......反之亦然?
什么Atomic*
班给你然而,提供了更高级的功能的方法,如incrementAndGet()
,compareAndSet()
,和其他人实现多个操作(Get /递增/集,测试/套)没有锁定。这就是为什么Atomic*
类非常强大。
还需要注意的是,使用Atomic*
类包装volatile
字段是从对象角度封装关键共享资源的好方法。这意味着开发人员不能仅仅处理该领域,假设它不共享可能会给引入竞争条件的field++;
或其他代码注入问题。
感谢您的回答 –
既然有人提到过它(既不在这里,也不在重复):w/Atomic类你有一个漂亮的方法lazySet。在大多数体系结构中,它比基本的易失性写入(但它不具有相同的语义)要好。基本上lazySet不需要刷新CPU写入缓冲区,这是非常好的,因为它们可以在CPU停止时刷新。 – bestsss