JavaでAtomicBooleanを使用する必要があるのはいつですか?


回答:


244

複数のスレッドがブール値を確認および変更する必要がある場合。例えば:

if (!initialized) {
   initialize();
   initialized = true;
}

これはスレッドセーフではありません。あなたはそれを修正することができますAtomicBoolean

if (atomicInitialized.compareAndSet(false, true)) {
    initialize();
}

51
それは実際の例のようには見えません-他のスレッドは完了していないtrueときに見ることができますinitialize()。したがって、他のスレッドがの完了を気にしない場合にのみ機能しinitialize()ます。
axtavt 2010

6
@axtavt:initialized1つだけのスレッドがinitialize()メソッドを呼び出すことを保証するためだけに使用されている場合、これは完全に有効な実際の例だと思います。明らかにinitialized真であることは、初期化は間違いなく、この場合には完了したので、ということではないかもしれないわずかに異なる用語が良いここになります。繰り返しますが、それはそれが何に使用されているかに依存します。
ColinD 2010

14
initStartedとinitCompletedには2つのブール値が必要です。最初のスレッドがinitStartedを設定してinitialise()を呼び出し、残りはinitCompletedがtrueになるまで待機します。
マーティン、

3
@Bozho- booleanフィールドへの読み取りと書き込みはアトミックなものですか?、今、volatileはbooleanフィールドの最新の値を提供します。つまり、実質的には?volatile booleanと同じではありませAtomicBooleanん。
TheLostMind 2014

2
@Martin:ブール値がtrueになるのを待つ直接的な方法はありません。追加のメカニズムが必要です。最も賢明なアプローチは、synchronizedブロックを使用することです。この場合、は不要になりAtomicBoolean、だけになりvolatile booleanます。(if(! this.initialized) { synchronized(this) { if(! this.initialized) { initialize(); this.initialized = true; } } }とマークinitializeされている場合、1つのスレッドのみがを呼び出し、他のすべてのスレッドが呼び出しを待機します。)initializedvolatile
ruakh

52

こちらが私が作成したメモ(ブライアンゲッツの本から)です。

AtomicXXXクラス

  • 非ブロッキングの比較とスワップの実装を提供する

  • ハードウェアが提供するサポート(IntelのCMPXCHG命令)を利用します。これらのアトミック同時実行APIを使用するコードで多数のスレッドが実行されている場合、オブジェクトレベルのモニター/同期を使用するコードよりもはるかに優れたスケーリングが可能です。Javaの同期メカニズムはコードを待機させるため、クリティカルセクションを通過するスレッドが多数ある場合、同期メカニズム自体の管理(待機、通知など)にかなりのCPU時間を費やします。新しいAPIはハードウェアレベルのコンストラクト(原子変数)と待機およびロックフリーアルゴリズムを使用してスレッドセーフを実装するため、同期の管理よりも「処理」に多くのCPU時間が費やされます。

  • スループットが向上するだけでなく、デッドロックや優先順位の逆転などの活性の問題に対する耐性も向上します。


34

アトミックブールを使用できる主な理由は2つあります。まず変更可能です。たとえば、それを参照として渡し、ブール値自体に関連付けられている値を変更できます。

public final class MyThreadSafeClass{

    private AtomicBoolean myBoolean = new AtomicBoolean(false);
    private SomeThreadSafeObject someObject = new SomeThreadSafeObject();

    public boolean doSomething(){
         someObject.doSomeWork(myBoolean);
         return myBoolean.get(); //will return true
    }
}

そしてsomeObjectクラスで

public final class SomeThreadSafeObject{
    public void doSomeWork(AtomicBoolean b){
        b.set(true);
    }
}

さらに重要なのは、そのスレッドセーフであり、クラスを保守している開発者に、この変数が変更されて複数のスレッドから読み取られることが予想されることを示すことができます。AtomicBooleanを使用しない場合は、使用しているブール変数を揮発性として宣言するか、フィールドの読み取りと書き込みの前後で同期して、ブール変数を同期する必要があります。


4
神の愛のために、それはオブジェクト自体の可変性を示すことだけでした。具体的にはデモンストレーションのために書いたものです。
John Vint

そしてさらに、それが起こっていたすべてだった場合は、はい、それは常にtrueを返します
John Vint

それがスレッドセーフであるかどうかは証明されていません。コードスニペットを完成させて、クラスを非常にスレッドセーフにすることができますが、それだけでは意味がありません。
John Vint

1
揮発性だけでは不十分だと思います。メインメモリから直接同じ値を読み書きする2つのスレッドが、それらのスレッド間で同期が行われていない状況について考えてください。並行性の問題が発生する可能性があります。
Shay Tsadok 2015年

1
その仮定を行うのに十分なOPからのコンテキストがありませんでしたが、アトミックセットとチェック操作には十分ではありません。言うまでもなく、もちろん状況によっては、揮発性が十分でない場合もあります。
John Vint 2015年

18

AtomicBooleanクラスはあなたがアトミックに更新できるというブール値を与えます。ブール変数にアクセスする複数のスレッドがある場合に使用します。

java.util.concurrent.atomicパッケージの概要はあなたにこのパッケージのクラスは何をすべきかの良いハイレベルの記述を与え、ときにそれらを使用します。また、Brian Goetz 著のJava Concurrency in Practiceもお勧めします。


5

パッケージの説明からの抜粋

パッケージjava.util.concurrent.atomic description:単一の変数でロックフリーのスレッドセーフなプログラミングをサポートするクラスの小さなツールキット。[...]

これらのメソッドの仕様により、最新のプロセッサで利用できる効率的なマシンレベルのアトミック命令を実装で使用できるようになります。[...]

クラスAtomicBoolean、AtomicInteger、AtomicLong、およびAtomicReferenceのインスタンスはそれぞれ、対応する型の単一の変数へのアクセスと更新を提供します。[...]

アトミックのアクセスと更新のメモリ効果は、一般に揮発性物質の規則に従います。

  • getには、揮発性変数を読み取るメモリ効果があります。
  • setには、揮発性変数の書き込み(割り当て)によるメモリー効果があります。
  • weakCompareAndSetは、変数をアトミックに読み取り、条件付きで書き込み、その変数に対する他のメモリ操作に関して順序付けられますが、それ以外は通常の不揮発性メモリ操作として機能します。
  • compareAndSetおよびgetAndIncrementなどの他のすべての読み取りおよび更新操作には、揮発性変数の読み取りと書き込みの両方のメモリ効果があります。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.