19

可能重复:
Java:volatile boolean vs AtomicBoolean

什么时候适合使用volatile原语(例如boolean, integeror long)而不是AtomicBoolean, AtomicIntegeror AtomicLong,反之亦然?

4

4 回答 4

19

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

例如:

if (volatileBoolean) {
    volatileBoolean = !volatileBoolean;
}

可能会在多线程环境中产生问题,因为变量可能会在两行之间发生变化。如果您需要测试和分配是原子的,您可以使用:

atomicBoolean.compareAndSet(true, false);
于 2012-10-12T12:29:10.093 回答
17

如果您只想设置或获取值,则使用普通的 volatile 会更简单、更有效。(但不能获取&设置值)

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

于 2012-10-12T12:30:31.877 回答
9

这些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;
   }

所以。

何时适合使用 volatile 原语(例如 boolean、integer 或 long)而不是 AtomicBoolean、AtomicInteger 或 AtomicLong

如果您所做的只是获取和设置 aAtomic*那么您还不如只使用一个volatile字段。

……反之亦然?

然而,这些Atomic*类为您提供的是提供更高级功能的方法,例如incrementAndGet()compareAndSet()和其他实现多个操作(get/increment/set、test/set)而无需锁定的方法。这就是Atomic*类如此强大的原因。

同样重要的是要注意,volatile使用类包装字段Atomic*是从对象角度封装关键共享资源的好方法。这意味着开发人员不能只处理该字段,假设它不共享,可能会field++;在引入竞争条件的代码或其他代码中注入问题。

于 2012-10-12T12:48:04.777 回答
7

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

根据我的经验,人们添加 volatile 以在线程之间共享值。然后,其他人开始修改该值。大多数时候,这是有效的。但是在生产中,您会开始遇到难以追踪的奇怪错误。计数器增加 100'000 次(测试只增加 10 次)但最终达到 99'997。在 Java 1.4 中,长值可能会被破坏,非常非常罕见。

Atomic*另一方面,助手类只产生很小的开销,而且它们总是像宣传的那样工作。

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

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

*:过早的优化从来都不是一个好的理由。

于 2012-10-12T12:43:36.853 回答