この記事では、AtomicInteger アトミック クラスの役割 (コード例) を紹介します。これには特定の参考価値があります。必要な友人は参照できます。お役に立てば幸いです。 。 ヘルプ。
AtomicInteger アトミック クラスの役割
マルチスレッド操作、Synchronized ではパフォーマンスのオーバーヘッドが大きすぎるため、カウントはアトミック操作ではありません。 count は読み取り、変更、書き込みの 3 つのステップを経る必要があるためです。
count はアトミックな操作ではありません。 count は読み取り、変更、書き込みの 3 つのステップを経る必要があるためです。
これを行うことができます:
public synchronized void increase() { count++; }
同期ロックは排他的です。つまり、他のスレッドが実行中の場合、現在のスレッドは待機することしかできません。
CAS を使用した操作
CAS には 3 つのオペランドがあります:
メモリ値 V 古い期待値 変更される新しい値 B 複数のスレッドが試行するとき CAS が使用される場合同じ変数を同時に更新する場合、スレッドのうちの 1 つだけが変数の値を更新できます (A とメモリ値 V が同じ場合、メモリ値 V を B に変更します)。他のスレッドは失敗します。失敗したスレッドはハングされず、代わりに、競争に失敗したことが通知され、再試行することができます (または何もしないこともできます)。
CAS には 2 つの状況があることがわかります。
メモリ値 V が期待値 A と等しい場合、メモリ値は B に変更され、操作は成功します。 !
メモリ値 V が期待値 A と等しくない場合、一般に 2 つの状況が考えられます:
再試行 (スピン) して何もしない
CAS を理解する 核心は次のとおりです。 :
CAS はアトミックです。比較と交換を見ると 2 つの操作があるように思われるかもしれませんが、結局のところアトミックです。
アトミック変数クラスは java.util.concurrent.atomic パッケージの下にあります。全体として、非常に多くの
基本型があります:
AtomicBoolean: Boolean AtomicInteger: Integer AtomicLong : Long 整数型
Array:
AtomicIntegerArray: 配列内の整数型 AtomicLongArray: 配列内の Long 整数型 AtomicReferenceArray: 配列内の参照型
参照型:
AtomicReference: 参照型 AtomicStampedReference: バージョン番号付きの参照型 AtomicMarkableReference: マーク ビット付きの参照型
オブジェクトのプロパティ
AtomicIntegerFieldUpdater: オブジェクトのプロパティは整数型 AtomicLongFieldUpdater: オブジェクトの属性はLong 整数 AtomicReferenceFieldUpdater: オブジェクトの属性は参照型です。
JDK8 の新しい DoubleAccumulator、LongAccumulator、DoubleAdder、LongAdder
は、AtomicLong およびその他のクラスの改良です。たとえば、同時実行性の高い環境では、LongAccumulator と LongAdder は AtomicLong よりも効率的です。 Atomic パッケージ内のクラスは、基本的に Unsafe を使用して実装されたラッパー クラスです。
Unsafe には、気に入ったメソッド (CAS) がいくつかあります。
// 第一和第二个参数代表对象的实例以及地址,第三个参数代表期望值,第四个参数代表更新值 public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5); public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5); public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);
アトミック変数クラスの使用
class Count{ // 共享变量(使用AtomicInteger来替代Synchronized锁) private AtomicInteger count = new AtomicInteger(0); public Integer getCount() { return count.get(); } public void increase() { count.incrementAndGet(); } }
ABAアトミッククラスの問題
以下の操作は正常に実行できますが、この場合どのような問題が発生しますか? ?スレッド C はスレッド A とスレッド B によって変更されたカウント値を知ることができないため、危険です。
今、変数 count=10 があります。現在、A、B、C という 3 つのスレッドがあります。スレッド A とスレッド C は同時に count 変数を読み取るため、メモリ値と期待値はスレッド A とスレッド C 両方とも 10 です。この時点で、スレッド A は CAS を使用してカウント値を 100 に変更します。変更後、この時点でスレッド B が入ってきて、カウントの値を 100 として読み取ります (メモリ値とスレッド C が実行権を取得し、メモリ値が 10 であり、期待値も 10 であることがわかります。カウント値を 11 に変更します。
ABA 問題を解決する
ABA 問題を解決するには、JDK が提供する AtomicStampedReference クラスと AtomicMarkableReference クラスを使用できます。
簡単に言えば、このオブジェクトのバージョンを提供し、このバージョンが変更されると、自動的に更新されます。
原理はおそらく次のとおりです。Pair オブジェクトが維持され、Pair オブジェクトにはオブジェクト参照とスタンプ値が格納されます。 CAS が 2 つのペア オブジェクトを比較するたびに、
LongAdder は AtomicLong よりも優れたパフォーマンスを発揮します。
AtomicLong を使用すると、高い同時実行性のもとで、多数のスレッドが同じアトミック変数を同時に更新しようと競合します。ただし、同時実行により 1 つのスレッドの CAS のみが成功するため、他のスレッドは引き続きスピンを試行し、CAS 操作を試行し、大量の CPU リソースを浪費します。
LongAdder を要約すると、内部のコア データ値が配列 (Cell) に分割され、各スレッドがそれにアクセスすると、ハッシュやその他のアルゴリズムを通じてカウントするための数値の 1 つにマッピングされ、最終的なカウント結果は、この配列の合計と累積です。
簡単に言えば、1 つの値が複数の値に分散されるため、同時実行時の圧力が分散され、パフォーマンスが向上します。
以上がAtomicInteger アトミック クラスの役割の概要 (コード例)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。