1.CASの概要
-
CASとは何ですか?
CASのフルネームはコンペアアンドスワップ、つまりコンペアアンドスワップです。アトミック命令を使用してマルチスレッド同期を実現します。メモリアドレスに格納されている元の値を指定されたメモリアドレスと比較します。これらが等しい場合のみ、指定されたメモリアドレスが交換されます。期待値とメモリ内の値。この操作はアトミック操作です。等しくない場合は、メモリアドレスに格納されている元の値が取得されます。 -
CASのプロセスCASはロックフリーアルゴリズムであり、3つのキーオペランド、メモリアドレス、古いメモリの期待値、および更新される新しい値があります。メモリ値が古いメモリの期待値と等しい場合メモリ、メモリはです。の値は新しい値に更新されます。
3.オプティミスティックロックとペシミスティックロック
CASはオプティミスティックロックに属します。オプティミスティックロックとは、毎回ロックせずに、競合がないと仮定して操作を完了することです。競合が失敗した場合は、成功するまで再試行します。
同期は悲観的なロックです。スレッドがロックを取得した後、他のスレッドはスレッドがロックを解放するのを待つ必要があります。パフォーマンスが低下します。
次に、AtomicIntegerコードは
、Javaではa ++がアトミック操作ではないことを示しています。単純なa ++操作には3つの操作が含まれます。変数aのメモリ値を取得し、変数a + 1を書き込み、新しい値をメモリに書き込みます。ここでは2つのメモリアクセスが含まれます。マルチスレッド環境では、同時実行の安全性の問題が発生します。
AtomicIntegerは、CASロックフリーアルゴリズムを内部で使用するアトミック操作クラスです。
ここでは、その内部実装を分析します。
AtomicInteger atomicInteger = new AtomicInteger(0);
atomicInteger.getAndSet(1);
コード
のコピー ここでの静的コードブロックは、AtomicIntegerオブジェクトが初期化される前に実行され、「開始アドレス」に対するAtomicIntegerオブジェクトの値フィールドのオフセットを取得します。 "AtomicIntegerオブジェクト、Javaの"メモリに格納されているオブジェクトのレイアウトは、オブジェクトヘッダー(ヘッダー)、インスタンスデータ(インスタンスデータ)、および配置パディング(パディング)の3つの領域に分割できます。「開始アドレス」のオフセットオブジェクトヘッダーのオフセットです。
static { try {
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField( "value"));
} catch(Exception ex){throw new Error(ex);}
}
public final int getAndSet(int newValue){ return unsafe.getAndSetInt(this、 valueOffset、newValue); }メモリアドレス(var2)を介して毎回コードをコピー し、メモリからメモリ内の元の値(var5)を取得してから、メモリ内の元の値(var5)を指定されたメモリアドレスにリサイクルします。 (var2)比較し、等しい場合は指定された期待値(var4)を更新し、等しくない場合は成功するまで再試行し、最後に古いメモリ値var5に戻ります。// var1はAtomicIntegerオブジェクト、var2はメモリアドレス値、var4は指定された期待値public final int getAndSetInt(Object var1、long var2、int var4){ int var5; do { // unsafe.getIntVolatileはローカルメソッドを呼び出しますメモリ値を取得するにはvar5 = this.getIntVolatile(var1、var2); } while(!this.compareAndSwapInt(var1、var2、var5、var4));
returnvar5;
}
コード3をコピーします。短所 -
ABA問題
CASは、操作中に変数の値が変更されたかどうかをチェックし、変更されていない場合は値を更新しますが、問題が発生します。最初の値はA、次にBになり、最後に再びAになります。最終値はまだAであるため、この値が変更されていないことを確認した後、実際にはこの値は実際に変更されています。この問題を解決するために、操作を実行するたびにバージョン番号が追加され、各操作はバージョン番号と特定の値の2つの値であり、A-> B->問題は1Aになります- > 2B-> 3A。AtomicStampedReferenceクラスは、ABA問題を解決するためにjdkで提供されます。これは、Pairの内部クラスで実装されます。これには、バージョン番号と参照を表す2つの属性が含まれます。compareAndSetでは、現在の参照が最初にチェックされ、次にバージョン番号フラグがチェックされます。すべてのみ値が等しい場合にのみ値が更新されます。 -
1つの共有変数のアトミック操作のみを保証できます。複数の共有変数を操作する場合、ループCASは操作のアトミック性を保証できません。現時点では、ロックを使用できます。java1.5以降、JDKはAtomicReferenceクラスを提供して、参照されるオブジェクト間のアトミック性を確保します。1つのオブジェクトに複数の変数を配置して、CAS操作を実行できます。 -
長いサイクルタイム
と高いCPUオーバーヘッド。同時実行性が高い場合、多くのスレッドが特定の変数を繰り返し更新しようとしても、更新が失敗すると、サイクルによってCPUに大きなプレッシャーがかかります。