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

Dav*_*ant 17 java concurrency

可能重复:
Java:volatile boolean vs AtomicBoolean

什么时候使用volatile原语(例如boolean,integerlong)代替AtomicBoolean,AtomicIntegerAtomicLong反之亦然?

ass*_*ias 17

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

例如:

if (volatileBoolean) {
    volatileBoolean = !volatileBoolean;
}
Run Code Online (Sandbox Code Playgroud)

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

atomicBoolean.compareAndSet(true, false);
Run Code Online (Sandbox Code Playgroud)

  • `volatileBoolean =!volatileBoolean;`只能单独出现一个线程问题. (6认同)
  • @DavidGrant实际上更可能是一个3步操作:读取值,否定,赋值. (5认同)
  • 共有三个步骤;1) 获取 `易失性布尔值` 2) 翻转它 3) 设置`易失性布尔值`。步骤 1 和步骤 3 之间可以有任意数量的线程 (2认同)

Pet*_*rey 16

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

如果您需要更多操作,如getAndIncrement或compareAndSwap,则需要使用AtomicXxxx类.


Gra*_*ray 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;
   }
Run Code Online (Sandbox Code Playgroud)

所以.

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

如果您正在做的就是获取并设置一个,Atomic*那么您可能只需要一个volatile字段.

......反之亦然?

什么Atomic*课给你不过是提供更先进的功能,如方法incrementAndGet(),compareAndSet()其他人实现多个操作(Get /递增/集,测试/套),并没有锁.这就是为什么Atomic*课程如此强大.

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

  • 比标记为“答案”的解释更好。 (2认同)

Aar*_*lla 7

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

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

Atomic*助手类,而另一方面,征收只是一个小的开销,并为标榜他们总是工作.

因此,除非你有一个很好的理由(*),否则volatile总是更喜欢Atomic*辅助类.

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

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