AtomicBoolean做了哪些volatile boolean不能做到的事情?


当前回答

Volatile boolean vs AtomicBoolean

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

如果你所做的只是获取和设置一个Atomic*,那么你也可以用一个volatile字段来代替。

AtomicBoolean做了哪些volatile boolean不能做到的事情?

原子类为您提供了提供更高级功能的方法,例如用于数字的incrementAndGet(),用于布尔值的compareAndSet(),以及其他实现多重操作(get/increment/set, test/set)而无需锁定的方法。这就是为什么Atomic*类如此强大。

例如,如果多个线程使用++使用下面的代码,就会出现竞争条件,因为++实际上是:get、increment和set。

private volatile value;
...
// race conditions here
value++;

然而,下面的代码将在多线程环境中安全工作,没有锁:

private final AtomicLong value = new AtomicLong();
...
value.incrementAndGet();

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

其他回答

这里的很多答案都过于复杂,令人困惑,或者是错误的。例如:

如果你有多个线程修改布尔值,你应该使用AtomicBoolean。

一般来说,这是不正确的。

如果一个变量是volatile,那么对它的每个原子访问都是同步的……

这是不正确的;同步完全是另一回事。

简单的答案是,AtomicBoolean允许您在某些操作中防止竞争条件,这些操作需要读取值,然后根据所读取的内容写入值;它使这些操作具有原子性(即它删除了变量可能在读和写之间发生变化的竞态条件)——因此得名。

如果你只是读写变量,写操作并不依赖于你刚刚读取的值,volatile就可以很好地工作,即使是多线程。

你不能将compareAndSet, getAndSet作为带有volatile boolean的原子操作(除非你同步它)。

如果有多个线程访问类级别变量,则 每个线程都可以在其线程本地缓存中保留该变量的副本。

将变量设置为volatile将防止线程将变量的副本保存在线程本地缓存中。

原子变量是不同的,它们允许对其值进行原子修改。

Volatile关键字保证共享该变量的线程之间的happens-before关系。它不能保证2个或更多的线程在访问布尔变量时不会相互中断。

Volatile boolean vs AtomicBoolean

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

如果你所做的只是获取和设置一个Atomic*,那么你也可以用一个volatile字段来代替。

AtomicBoolean做了哪些volatile boolean不能做到的事情?

原子类为您提供了提供更高级功能的方法,例如用于数字的incrementAndGet(),用于布尔值的compareAndSet(),以及其他实现多重操作(get/increment/set, test/set)而无需锁定的方法。这就是为什么Atomic*类如此强大。

例如,如果多个线程使用++使用下面的代码,就会出现竞争条件,因为++实际上是:get、increment和set。

private volatile value;
...
// race conditions here
value++;

然而,下面的代码将在多线程环境中安全工作,没有锁:

private final AtomicLong value = new AtomicLong();
...
value.incrementAndGet();

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