使用volatile原语而不是原子变量有什么区别?

时间:2012-10-12 12:24:07

标签: java concurrency

  

可能重复:
  Java: volatile boolean vs AtomicBoolean

何时使用volatile原语(例如booleanintegerlong)代替AtomicBooleanAtomicIntegerAtomicLong,反之亦然?

4 个答案:

答案 0 :(得分:17)

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

例如:

if (volatileBoolean) {
    volatileBoolean = !volatileBoolean;
}

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

atomicBoolean.compareAndSet(true, false);

答案 1 :(得分:15)

如果要设置或获取值,则使用普通的volatile更简单,更高效。 (但不能得到&设定值)

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

答案 2 :(得分:8)

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

如果你所做的只是获取并设置Atomic*,那么你也可以改为使用volatile字段。

  

......反之亦然?

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

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

答案 3 :(得分:7)

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

根据我的经验,人们添加volatile来在线程之间共享一个值。然后,其他人开始修改该值。大多数时候,这都有效。但在生产中,你开始出现奇怪的错误,这些错误很难追查。计数器增加100'000次(测试只增加10次)但最终为99'997。在Java 1.4中,长值可能真的很少被破坏。

另一方面,Atomic*帮助程序类只需要很小的开销,而且它们总是像宣传的那样工作。

因此,除非您有充分的理由(*)使用volatile,否则请始终使用Atomic*辅助类。

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

*:过早优化绝不是一个好理由。