易失性布尔值与原子布尔值

新手上路,请多包涵

AtomicBoolean 做了哪些 volatile 布尔值无法实现的功能?

原文由 JeffV 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 591
2 个回答

他们只是完全不同。考虑这个 volatile 整数的例子:

 volatile int i = 0;
void incIBy5() {
    i += 5;
}

如果两个线程同时调用该函数, i 之后可能为 5,因为编译后的代码将与此有些相似(除非您无法在 int 上同步):

 void incIBy5() {
    int temp;
    synchronized(i) { temp = i }
    synchronized(i) { i = temp + 5 }
}

如果一个变量是 volatile 的,对它的每个原子访问都是同步的,但实际上什么是原子访问并不总是很明显。使用 Atomic* 对象,可以保证每个方法都是“原子的”。

因此,如果您使用 AtomicIntegergetAndAdd(int delta) ,您可以确定结果将是 10 。同样,如果两个线程同时否定 boolean 变量,使用 AtomicBoolean 您可以确定它之后具有原始值,使用 volatile boolean ,你不能。

因此,当您有 多个线程 修改一个字段时,您需要使其原子化或使用显式同步。

volatile 的目的是不同的。考虑这个例子

volatile boolean stop = false;
void loop() {
    while (!stop) { ... }
}
void stop() { stop = true; }

如果您有一个线程正在运行 loop() 并且另一个线程正在调用 stop() ,如果您省略 volatile --- ,您可能会遇到无限循环,因为第一个线程可能会缓存止损值。在这里, volatile 提示编译器在优化时要更加小心。

原文由 Cephalopod 发布,翻译遵循 CC BY-SA 3.0 许可协议

当所述字段仅由其所有者线程更新并且该值仅由其他线程读取时,我使用易失性字段,您可以将其视为发布/订阅场景,其中有许多观察者但只有一个发布者。但是,如果那些观察者必须根据字段的值执行一些逻辑,然后推回一个新值,那么我会选择 Atomic* 变量或锁或同步块,无论哪种最适合我。在许多并发场景中,它归结为获取值、将其与另一个值进行比较并在必要时进行更新,因此 Atomic* 类中存在 compareAndSet 和 getAndSet 方法。

查看 java.util.concurrent.atomic 包的 JavaDocs 以获得 Atomic 类的列表以及它们如何工作的出色解释(刚刚了解到它们是无锁的,因此它们比锁或同步块有优势)

原文由 teto 发布,翻译遵循 CC BY-SA 2.5 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题