Java AtomicInteger クラスにはメソッドがあります -
boolean weakCompareAndSet(int expect,int update)
そのドキュメントには次のように書かれています。
誤って失敗する可能性があります。
ここでの「見せかけの失敗」とはどういう意味ですか?
偽りの: 明らかな理由もなく
atomic
パッケージjavadocによると:
アトミック クラスは、適用範囲が限定されたメソッド weakCompareAndSet もサポートします。
一部のプラットフォームでは、weak バージョンは通常の場合の compareAndSet よりも効率的ですが、weakCompareAndSet メソッドの任意の呼び出しが誤って (つまり、明らかな理由もなく) false を返す可能性があるという点で異なります。
偽の戻り値は、必要に応じて操作を再試行できることを意味するだけであり、変数が expectedValue を保持し、他のスレッドも変数を設定しようとしていないときに繰り返し呼び出しが最終的に成功するという保証に依存しています。
(このような誤った障害は、たとえば、期待値と現在の値が等しいかどうかに関係のないメモリ競合の影響が原因である可能性があります。)さらに、weakCompareAndSet は、同期制御に通常必要とされる順序保証を提供しません。
このスレッドによると、「ハードウェア/OS」が原因ではなく、weakCompareAndSet で使用される基本的なアルゴリズムが原因です。
現在の値 == 期待される値の場合、weakCompareAndSet は指定された更新された値に値をアトミックに設定します。誤って失敗する可能性があります。
compareAndSet() や AtomicX の他の操作とは異なり、weakCompareAndSet() 操作は、事前発生順序付けを作成しません。
したがって、weakCompareAndSet によって引き起こされた AtomicX の更新をスレッドが確認したからといって、weakCompareAndSet() の前に発生した操作とスレッドが適切に同期されているとは限りません。
おそらくこのメソッドを使用したくないでしょうが、代わりに compareAndSet; を使用する必要があります。なぜなら、weakCompareAndSet が compareAndSet よりも高速であるケースはほとんどなく、compareAndSet ではなく weakCompareAndSet を使用してコードを最適化しようとすると、微妙で再現が困難な同期エラーがコードに導入されるケースが多数あるからです。
発生前の順序付けに関する注意:
Java メモリ モデル (JMM) は、変数を読み取るスレッドが別のスレッドで書き込みの結果を確認することが保証される条件を定義します。
JMM は、事前発生と呼ばれるプログラムの操作に関する順序付けを定義します。
スレッド間で発生する前の順序付けは、共通ロックで同期するか、共通の揮発性変数にアクセスすることによってのみ作成されます。
発生前の順序付けがない場合、Java プラットフォームには、あるスレッドでの書き込みが別のスレッドでの同じ変数の読み取りに見えるようになる順序を遅延または変更する大きな自由度があります。
これは、現在期待される値が含まれていても、false を返す (そして新しい値を設定しない) 可能性があることを意味します。
言い換えれば、メソッドは何もせず、明白な理由もなく false を返す可能性があります...
これが strong よりもパフォーマンス上の利点を持つ可能性がある CPU アーキテクチャがありますCompareAndSet()
。
なぜこのようなことが起こるのかについて、もう少し具体的な詳細。
一部のアーキテクチャ (新しい ARM など) は、Load Linked (LL)/Store Conditional (SC) 命令セットを使用して CAS 操作を実装します。LL 命令は、メモリ位置に値をロードし、アドレスをどこかに「記憶」します。記憶されたアドレスの値が変更されていない場合、SC 命令はそのメモリ位置に値を格納します。ハードウェアは、いくつかの理由が考えられます (理由は CPU アーキテクチャによって異なる可能性があります)。
weakCompareAndSet の適切な使用例は、パフォーマンス カウンターです。順序付けは不要で、更新率が高くなります (したがって、順序付けは、順序付けが弱いシステムでは問題になります) が、高負荷下ではカウントをドロップしません (内容がぎっしり詰まったパフォーマンス カウンターは、すべての 99% をドロップする可能性があります)。カウントし、基本的に、競合していないカウンターに対するカウンターの値をランダムのままにします)。