什么时候最好在Java而不是AtomicBoolean中使用volatile boolean?

Jas*_*n S 54 java concurrency atomic volatile

我已经查看了SO中的其他volatile和Atomicxxxx问题(包括这个),并阅读了java.util.current.atomic的描述,我对细微差别不太满意.

如果我在尝试使用volatile boolean和之间做出决定AtomicBoolean,除了AtomicBoolean提供的原子读取 - 修改 - 写入操作之外是否存在实际差异?(例如compareAndSet()getAndSet())

假设我有

volatile boolean flag;
Run Code Online (Sandbox Code Playgroud)

然后一个或多个线程设置标志(但不清除它).如果我有一个线程读取标志,如果设置,执行操作,然后清除标志,是否volatile足够?

AtomicBoolean的成本是否高于volatile布尔值

  • 记忆空间
  • 性能命中(volatile boolean似乎需要内存防护,AtomicBoolean似乎需要内存防护+根据java.util.current.atomic描述对CAS操作进行一些小锁定)

我的直觉调用是使用AtomicBoolean并且是安全的,但我想了解是否有任何情况可以使用volatile boolean(例如,如果我有数千个实例,性能是一个问题).

biz*_*lop 72

之间的主要区别AtomicBooleanvolatile从实际的角度来看是,比较并设置操作不是原子与volatile变量.

 volatile boolean b;

 void foo() {
   if( b ) {
     //Here another thread might have already changed the value of b to false
     b = false;
   }
 }
Run Code Online (Sandbox Code Playgroud)

但是看到所有并发写入都是幂等的并且您只从一个线程读取,这应该不是问题.

  • 用于提升幂等概念的+1 (9认同)
  • @Tom Hawtin - tackline比较和设置(或交换)一般来说都是一个操作,即使在Java中没有内置的实现,除了`Atomic*`类.http://en.wikipedia.org/wiki/Compare-and-set (2认同)
  • 在您的示例中,无论发生什么,结果都是错误的.一个更好的例子是`b =!b`.有两个线程翻转`b`它应该保持不变,但没有原子性,它可能会失败. (2认同)

Cow*_*wan 19

我不确定我是否完全同意这里的其他答案; biziclop的回答是正确的,但我不确定除非我们知道更多细节,否则我们可以断定你是安全的.

在简单的情况下,交错可能如下所示:

Thread 1 (writer)   Thread 2 (Writer)  Thread 3 (Reader)
-----------------   -----------------  -----------------
flag = true;
                                       if (flag) {
                    flag = true;
                                         flag = false;
                                         doStuff();
Run Code Online (Sandbox Code Playgroud)

这可能是罚款(第二组flagtrue无所谓,因为doStuff()仍然可能会看到任何线程2个需要做的事情.

但是,如果您反转线程3的顺序:

Thread 1 (writer)   Thread 2 (Writer)  Thread 3 (Reader)
-----------------   -----------------  -----------------
flag = true;
                                       if (flag) {
                                         doStuff();
                    flag = true;
                                         flag = false;
Run Code Online (Sandbox Code Playgroud)

然后线程2的更新可能会丢失.

当然,你需要同样小心线程2做的其他事情,以确保线程3可见.如果线程2需要设置其他状态,那么命令也很重要.

在简单的情况下,是的,你很好,但如果它变得比仅仅简单地轻弹标志更复杂,那么这就变得更难以推理.

  • 好点子.虽然值得一提的是,在第二种情况下,AtomicBoolean也无济于事.那么就需要完全成熟的同步. (7认同)
  • @Cowen:我从来没有见过这样的可视化交错,但它非常清楚.我在阅读线程代码时精神上做到这一点,但在解释线程代码中的竞争条件/弱点时,这是一种记录案例的好方法. (3认同)

Tom*_*ine 18

基本上所有AtomicBoolean都是一个volatile boolean对象.

每个对象的开销很小.可能无关紧要,但可能有更多内存进入缓存.

如果你需要使用AtomicBooleanFieldUpdater那么就会有相当多的性能开销.如果你不打算经常这样做(如attach在NIO中).

  • 它实际上是一个`volatile int`http://www.docjar.com/html/api/java/util/concurrent/atomic/AtomicBoolean.java.html (4认同)

sna*_*pop 7

这里有很多好消息.但是,我会添加另一个可能有用的差异.你可以有一个AtomicBooleans数组,但你不能(据我所知)有一系列易失性的布尔值.