2012-10-12 77 views
15

可能重复:
Java: volatile boolean vs AtomicBoolean在原子变量中使用volatile变量与变量之间有什么区别?

当它适合使用volatile原语(例如booleanintegerlong)代替AtomicBooleanAtomicIntegerAtomicLong,反之亦然?

+0

既然有人提到过它(既不在这里,也不在重复):w/Atomic类你有一个漂亮的方法lazySet。在大多数体系结构中,它比基本的易失性写入(但它不具有相同的语义)要好。基本上lazySet不需要刷新CPU写入缓冲区,这是非常好的,因为它们可以在CPU停止时刷新。 – bestsss

回答

17

可见性语义完全相同,使用原子基元的情况非常有用,当您需要使用它们的原子方法时。

例如:

if (volatileBoolean) { 
    volatileBoolean = !volatileBoolean; 
} 

可在多线程环境作为变量可以在两条线之间改变创建的问题。如果你需要测试&分配是原子,你可以使用:

atomicBoolean.compareAndSet(true, false); 
+6

'volatileBoolean =!volatileBoolean;'本身可能存在线程问题。 –

+0

@PeterLawrey好点。 – assylias

+1

因为否定布尔值是一个两步操作? –

12

使用纯挥发性更简单,更有效的,如果你想要做的是设置或获取价值。 (但没有得到&设置值)

如果你想要更多的操作,如getAndIncrement或compareAndSwap你需要使用AtomicXxxx类。

+1

感谢您的回答 –

+0

lazySet on atomic通常会赢得不稳定的'写入'(特别是TSO体系结构),但它具有不同的语义。 – bestsss

+0

lazySet速度更快,因为它不会停止CPU管道。 –

7

我们已经开始禁止在我们的资源中使用volatile,因为编写代码并不总是按预期工作。

根据我的经验,人们在线程之间添加volatile来共享一个值。然后,别人开始修改价值。大多数情况下,这是有效的。但在制作过程中,你会发现很难追查的奇怪错误。计数器增加100'000次(测试只增加10次),但最终为99'997。在Java 1.4中,很长时间的值可能会被破坏,真的很少。

另一方面,Atomic*帮助类仅施加很小的开销,并且它们始终按广告方式工作。

所以,除非你有很好的理由(*)使用volatile,否则总是更喜欢Atomic*助手类。

如果您不确切知道Atomic*辅助类中的每个字符的含义,那么您应该避免使用volatile

*:不成熟的优化从来就不是一个好的理由。

+0

感谢您的回答 –

+0

*“编写代码并不总是按预期方式工作,非常容易。”* =>您可以更具体吗?例如,你是否认为人们假设volatile会给出原子性保证? – assylias

+1

@assylias:我在我的答案中添加了一些例子。 –

7

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++;或其他代码注入问题。

+1

感谢您的回答 –

相关问题