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


当前回答

布尔基元类型是原子的,用于写和读操作,volatile保证happens before原则。因此,如果您需要一个简单的get()和set(),那么您不需要AtomicBoolean。

另一方面,如果你需要在设置一个变量的值之前执行一些检查,例如。"如果为真,则设置为假",那么您也需要原子地执行此操作,在这种情况下使用compareAndSet和AtomicBoolean提供的其他方法,因为如果您尝试使用volatile boolean实现此逻辑,则需要一些同步来确保get和set之间的值没有更改。

其他回答

记住成语——

READ - MODIFY- WRITE这个你不能用volatile实现

AtomicBoolean有一些方法可以原子地执行复合操作,而不必使用同步块。另一方面,volatile布尔值只能在同步块中执行复合操作。

读取/写入volatile boolean的内存效果分别与AtomicBoolean的get和set方法相同。

例如,compareAndSet方法将自动执行以下操作(没有同步块):

if (value == expectedValue) {
    value = newValue;
    return true;
} else {
    return false;
}

因此,compareAndSet方法将允许您编写保证只执行一次的代码,即使是从多个线程调用时也是如此。例如:

final AtomicBoolean isJobDone = new AtomicBoolean(false);

...

if (isJobDone.compareAndSet(false, true)) {
    listener.notifyJobDone();
}

保证只通知侦听器一次(假设没有其他线程将AtomicBoolean设置为true后再次设置为false)。

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

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

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

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

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

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

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

两者都是相同的概念,但在原子布尔中,它将为操作提供原子性,以防cpu切换发生在两者之间。

如果你只有一个线程修改你的布尔值,你可以使用一个volatile布尔值(通常你这样做是为了在线程的主循环中定义一个停止变量)。

但是,如果有多个线程修改布尔值,则应该使用AtomicBoolean。否则,以下代码是不安全的:

boolean r = !myVolatileBoolean;

该操作分两步完成:

读取布尔值。 写入布尔值。

如果其他线程修改了#1到2#之间的值,您可能会得到错误的结果。AtomicBoolean方法通过原子地执行步骤#1和#2来避免这个问题。