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();
_
アトミックオブジェクトは Compare and Swap メカニズムを使用してアトミックにします-つまり、値があったことを保証できます指定したとおり、現在が新しい値になります。
投稿したコードは、現在の値を以前よりも1に設定しようとし続けています。別のスレッドもget
を実行した可能性があり、それを設定しようとしていることも覚えておいてください。 2つのスレッドが互いに競合して値を変更すると、インクリメントの1つが失敗する可能性があります。
次のシナリオを検討してください。
get
を呼び出し、値_1
_を取得します。next
を_2
_と計算します。get
を呼び出し、値_1
_を取得します。next
を_2
_と計算します。アトミックのため-1つのスレッドのみが成功します、他のスレッドはfalse
からcompareAndSet
を受け取り、移動します再び。
このメカニズムが使用されなかった場合、両方のスレッドが値をインクリメントして、実際には1つのインクリメントのみが実行される可能性があります。
混乱を招く無限ループfor(;;)
は、多数のスレッドが同時に変数に書き込んでいる場合にのみ実際にループします。非常に大きな負荷がかかると、数回ループする可能性がありますが、非常に速く完了するはずです。
for (;;)
は無限ループであるため、試行を再試行するだけです。