この記事では、Java プログラミングにおける cas 操作の概念、原則、使用法を例を通して分析します。これは一定の参考価値があり、必要な友人はそれについて学ぶことができます。
CAS は、メモリ内の共有データを操作する、最新の CPU で広くサポートされている特別な命令を指します。この命令は、メモリ内の共有データに対してアトミックな読み取りおよび書き込み操作を実行します。
この命令の動作プロセスを簡単に紹介します: まず、CPU はメモリ内で変更されるデータと期待値を比較します。次に、2 つの値が等しい場合、CPU はメモリ内の値を新しい値に置き換えます。それ以外の場合、操作は実行されません。最後に、CPU は古い値を返します。この一連の操作はアトミックです。複雑に見えますが、これらが Java 5 の同時実行メカニズムが元のロック メカニズムよりも優れている根本的な理由です。簡単に言えば、CAS の意味は、「元の値はどうあるべきだと思いますか。そうであれば、元の値を新しい値に更新してください。そうでない場合は変更せず、元の値が何であるかを教えてください。」ということです。 (この説明は『Java並行プログラミング実践編』より引用しています)
簡単に言うと、CASにはメモリ値V、古い期待値A、変更される新しい値Bの3つのオペランドがあります。期待値 A とメモリ値 V が同じである場合にのみ、メモリ値 V を B に変更し、それ以外の場合は V を返します。これは、変更される前に他のスレッドが変更しないと考える楽観的なロックの考え方であり、変更される前に他のスレッドが変更するだろうと考えるのが悲観的なロックです。
以下の簡単な例を見てください:
if(a==b) { a++; }
a++ を実行する前に a の値が変更されたらどうなるかを想像してみてください。 a++ はまだ実行中ですか?この問題の原因は、マルチスレッド環境では a の値が不確実な状態にあるためです。このような問題はロックによって解決できますが、CAS はロックなしでも解決できます。
int expect = a; if(a.compareAndSet(expect,a+1)) { doSomeThing1(); } else { doSomeThing2(); }
こうすることで、aの値が変更されてもa++は実行されなくなります。
上記の書き方では、a!=expectの後、a++は実行されませんが、whileループ
while(true) { int expect = a; if (a.compareAndSet(expect, a + 1)) { doSomeThing1(); return; } else { doSomeThing2(); } }
を使用すれば問題ありません。上記の記述方法は、A++ 操作がない場合、ロックなしで実装されます。これは実際にはノンブロッキング アルゴリズムです。
Application
java.util.concurrent.atomic パッケージのほとんどのクラスは CAS 操作を使用し、その主要なメソッドのいくつかの実装を確認する例として AtomicInteger を取り上げます。 JDK ドキュメントの getAndSet メソッドの説明は次のとおりです。指定された値にアトミックに設定し、古い値を返します。アトミック メソッドが反映されるところは、compareAndSet に反映されます。compareAndSet がどのように実装されるかを見てみましょう:
public final int getAndSet(int newValue) { for (;;) { int current = get(); if (compareAndSet(current, newValue)) return current; } }
a++ 操作がどのように実装されるかを見てみましょう:
public final boolean compareAndSet(int expect, int update) { return unsafe.compareAndSwapInt(this, valueOffset, expect, update); }
++a 操作は、返される結果が異なることを除いて、a++ 操作と似ています
public final int getAndIncrement() { for (;;) { int current = get(); int next = current + 1; if (compareAndSet(current, next)) return current; } }
短所:
ウィキペディアが生きた例を挙げています -
これがABAの問題です。
3. プログラムのテストが複雑になり、注意しないと問題が発生する可能性があります。
CAS はロックを使用せずにアトミックな操作を実装するために使用できますが、ロックを導入せずに非常に単純な操作を行う場合は、非ブロックで操作を完了する必要がある場合は、CAS 操作の使用を検討することもできます。 CAS.複雑な操作に CAS を導入することはお勧めできません。これにより、プログラムが読みにくくなり、テストが困難になり、ABA の問題が発生します。
以上がJava での cas 操作の分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。