web-dev-qa-db-ja.com

AtomicIntegerの「比較して設定」はどのように機能しますか

AtomicIntegerは、CASとvolatile変数という2つの概念で機能します。

volatile変数を使用すると、現在の値がすべてのスレッドから見えるようになり、キャッシュされなくなります。

しかし、以下で説明するCAS(比較ANDセット)の概念について混乱しています。

_public final int getAndIncrement() {
    for (;;) {
        int current = get();
        int next = current + 1;
        if (compareAndSet(current, next))
            return current;
    }
 }
_

私の質問は、whatif(compareAndSet(current, next)falseを返すということです。値は更新されませんか?この場合、スレッドが以下のケースを実行しているときに何が起こるでしょう:

_private AtomicInteger count = new AtomicInteger();
count.incrementAndGet();
_
19
Onki

アトミックオブジェクトは Compare and Swap メカニズムを使用してアトミックにします-つまり、値があったことを保証できます指定したとおり、現在が新しい値になります。

投稿したコードは、現在の値を以前よりも1に設定しようとし続けています。別のスレッドもgetを実行した可能性があり、それを設定しようとしていることも覚えておいてください。 2つのスレッドが互いに競合して値を変更すると、インクリメントの1つが失敗する可能性があります。

次のシナリオを検討してください。

  1. スレッド1はgetを呼び出し、値_1_を取得します。
  2. スレッド1はnextを_2_と計算します。
  3. スレッド2はgetを呼び出し、値_1_を取得します。
  4. スレッド2はnextを_2_と計算します。
  5. 両方のスレッドが値を書き込もうとします。

アトミックのため-1つのスレッドのみが成功します、他のスレッドはfalseからcompareAndSetを受け取り、移動します再び。

このメカニズムが使用されなかった場合、両方のスレッドが値をインクリメントして、実際には1つのインクリメントのみが実行される可能性があります。

混乱を招く無限ループfor(;;)は、多数のスレッドが同時に変数に書き込んでいる場合にのみ実際にループします。非常に大きな負荷がかかると、数回ループする可能性がありますが、非常に速く完了するはずです。

19
OldCurmudgeon

for (;;)は無限ループであるため、試行を再試行するだけです。

8