web-dev-qa-db-ja.com

AtomicBooleanではなくJavaで揮発性ブール値を使用するのが望ましいのはいつですか?

私はSO( this one を含む)で他の揮発性対Atomicxxxxの質問を見て、 Java.util.currentの説明を読みました) .atomic 、そして私はニュアンスに全く満足していません。

_volatile boolean_とAtomicBooleanのどちらを使用するかを決定しようとしている場合、AtomicBooleanによって提供されるアトミックな読み取り/変更/書き込み操作以外に実際的な違いはありますか? (例:compareAndSet()およびgetAndSet()

私が持っていると仮定します

_volatile boolean flag;
_

次に、1つ以上のスレッドがフラグを設定します(ただし、フラグはクリアしません)。フラグを読み取る1つのスレッドがあり、設定されている場合、アクションを実行してからフラグをクリアする場合、volatileは適切ですか?

の点で、揮発性ブールよりもAtomicBooleanの方が高いコストがありますか?

  • メモリ空間
  • パフォーマンスヒット(_volatile boolean_はメモリフェンシングを必要とするように見え、AtomicBooleanはメモリフェンシング+ Java.util.current.atomicの説明にあるようにCAS操作のいくつかのマイナーロックを必要とするようです)

私の根本的な呼びかけは、AtomicBooleanだけで安全であることですが、代わりに_volatile boolean_を使用する状況があるかどうかを理解したいと思います(たとえば、何千ものインスタンスがあり、パフォーマンスが問題だった場合)。

54
Jason S

基本的にすべてのAtomicBooleanvolatile booleanオブジェクト内。

オブジェクトごとに小さなオーバーヘッドがあります。おそらく重要ではありませんが、キャッシュに入れるメモリが増える可能性があります。

AtomicBooleanFieldUpdaterを使用する必要がある場合は、パフォーマンスのオーバーヘッドが非常に多くなります。頻繁に使用しない場合でも問題ありません(NIOのattachと同様)。

17

実用的な観点からのAtomicBooleanvolatileの主な違いは、比較と設定の操作がvolatile変数でアトミックではないことです。

 volatile boolean b;

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

しかし、すべての同時書き込みがべき等であり、1つのスレッドからのみ読み取るので、これは問題になりません。

71
biziclop

ここで他の答えに完全に同意するかどうかはわかりません。ビジクロップの答えはそれに関しては正しいですが、詳細を知らない限り、あなたが安全だと結論付けることができるかどうかはわかりません。

単純なケースでは、インターリーブは次のようになります。

Thread 1 (writer)   Thread 2 (Writer)  Thread 3 (Reader)
-----------------   -----------------  -----------------
flag = true;
                                       if (flag) {
                    flag = true;
                                         flag = false;
                                         doStuff();

そして、これは問題ないかもしれません(flagからtrueの2番目のセットは問題ではありません。doStuff()は、おそらくスレッド2が実行する必要があるものをすべて表示するからです。

ただし、スレッド3の順序を逆にすると、次のようになります。

Thread 1 (writer)   Thread 2 (Writer)  Thread 3 (Reader)
-----------------   -----------------  -----------------
flag = true;
                                       if (flag) {
                                         doStuff();
                    flag = true;
                                         flag = false;

その後、スレッド2の更新が失われる可能性があります。

もちろん、スレッド3から見えるようにするために、スレッド2が行う他のことについても同様に注意する必要があります。スレッド2が設定する必要のある他の状態がある場合、順序もそこで重要になります。

単純なケースでは、はいあなたは大丈夫ですが、フラグを単純にフリックするだけでは複雑になる場合は、これは推論するのがはるかに難しくなります。

19
Cowan

ここには多くの良い情報があります。ただし、役立つ可能性のある別の違いを追加します。 AtomicBooleanの配列を持つことはできますが、(私の知る限り)揮発性ブールの配列を持つことはできません。

7
snapfractalpop

次に、1つ以上のスレッドがフラグを設定します(ただし、フラグはクリアしません)。フラグを読み取るスレッドが1つあり、設定されている場合、アクションを実行してからフラグをクリアする場合、揮発性は適切ですか?

はい、AtomicBooleanの特別な機能が必要ない場合は、揮発性を使用しても問題ありません。実際、これはvolatileの数少ない合理的な用途の1つです。

2
Sergei Tachenov