Javaの13個の原子操作クラスの紹介

3901 ワード

一、引用
JDK 1.5にjavaを追加します.util.CAS上に構築されたconcurrent(J.U.C)パッケージ.CASは非ブロッキングアルゴリズムの一般的な実装であり,synchronizedのようなブロッキングアルゴリズムに比べて性能が優れている.
DK1.5には下位層のサポートが導入され、int、long、オブジェクトの参照などのタイプでCASの操作が公開されており、JVMはそれらを下位層のハードウェアにコンパイルする最も有効な方法であり、CASを実行するプラットフォームでは、実行時にそれらを対応するマシンコマンドにコンパイルする.javaでutil.concurrent.atomicパッケージの下にあるすべての原子変数タイプ、例えばAtomicIntegerは、これらの下位層のJVMを使用して、デジタルタイプの参照タイプに効率的なCAS操作を提供することをサポートしています.
二、Java原子類の紹介
atomicパッケージ中の13種類のクラスは、4種類の原子更新方式に属する.
  • (1)原子更新基本タイプ
  • (2)原子更新配列
  • (3)原子更新参照
  • (4)原子更新属性
  • atomicパッケージ内のクラスは基本的にUnsafeで実現したパッケージクラスである.
    1.原子更新基本タイプ
  • AtomicBoolean:原子更新ブール型.
  • AtomicInteger:原子更新型.
  • AtomicLong:原子更新長整型.

  • このクラスはAtomicIntegerで説明します.
    AtomicIntegerは原子操作をサポートするIntegerクラスで、AtomicIntegerタイプ変数の増加と減少操作が原子的であることを保証し、複数のスレッドでのデータの不一致の問題が発生しない.AtomicIntegerを使用しない場合、同じIDが同時取得されないように、順次取得されるIDを実現するには、取得のたびにロック操作を行う必要があります.
  • int addAndGet(int delta)は、入力された値をインスタンスの値に原子的に加算し、結果を返します.
  • boolean compareAndSet(int expect,int update)入力値が予想値に等しい場合、その値を原子的に入力値に設定する.
  • int getAndIncrement()現在の値を原子的に1加算し、ここでは自己増加前の値を返すことに注意してください.
  • void lazySet(int newValue)は最終的にnewValueに設定され、lazySetを使用して値を設定すると、他のスレッドがその後のわずかな時間で古い値を読むことができる可能性があります.
  • int getAndSet(int newValue)は、newValueの値に原子的に設定され、古い値を返します.

  • ではgetAndIncrementはどのように原子操作を実現しているのでしょうか.
    public final int getAndIncrement() { 
        for (;;) { 
            int current = get(); 
            int next = current + 1; 
            if (compareAndSet(current, next)) 
                return current; 
        } 
    }
    

    その実現原理はデッドサイクル+CASであることが分かる.
    2.原子更新配列
    配列内のある要素を原子的に更新し,Atomicパケットは以下の3つのクラスを提供する.
  • AtomicIntegerArray:原子更新型配列内の要素.
  • AtomicLongArray:原子更新長整数配列の要素.
  • AtomicReferenceArray:参照タイプ配列内の要素を原子更新します.

  • AtomicIntegerArrayクラスの提供方法は次のとおりです.
  • int addAndGet(int i,int delta)入力値を配列中のインデックスiの要素に原子的に加算
  • .
  • boolean compareAndSet(int i,int expect,int update)現在値が予想値に等しい場合、配列位置iの要素を原子的にupdate値に設定.

  • 3.原子更新参照タイプ
    原子更新基本タイプのAtomicIntegerは、1つの変数しか更新できません.複数の変数を原子で更新する場合は、この原子を使用して参照タイプが提供するクラスを更新する必要があります.Atomicパッケージには、以下の3つのクラスが用意されています.
  • AtomicReference:原子更新参照タイプ.
  • AtomicReferenceFieldUpdater:原子更新参照タイプのフィールド.
  • AtomicMarkableReference:原子更新タグビット付き参照タイプ.

  • 4.原子更新属性
    クラス内のフィールドを原子的に更新する必要がある場合は、原子更新フィールドクラスを使用する必要があります.Atomicパッケージには、次の3つのクラスが原子フィールド更新を行います.
  • AtomicIntegerFieldUpdater:原子更新型のフィールドの更新器.
  • AtomicLongFieldUpdater:原子更新長整数フィールドの更新器.
  • AtomicStampedReference:原子更新バージョン番号付き参照タイプ.このクラスは整数値を参照に関連付け、原子の更新データとデータのバージョン番号に使用でき、CASを使用して原子の更新を行う場合に発生するABAの問題を解決することができます.

  • 三、原子類の応用シーン
    原子変数は、ロックまたは他の同期メカニズムを使用して値への同時アクセスを保護する必要はありません.すべての操作はCAS原子に基づいて操作される.彼は、データの不一致なエラーを生じずに、マルチスレッドが同じ時間に1つの原子変数を操作することを保証し、同期メカニズムを使用して保護される通常の変数よりも性能が優れている.例えば、マルチスレッド環境で回数を統計すれば原子変数を使用することができる.具体的なシーンは以下のようにまとめられています.
  • マルチスレッド環境では、synchronizedをこのキーワードで置き換えることができる場合が多い.
  • 同時流量制限:高同時のシーンでは、インタフェースの流量を制限し、同時の数を超えるしきい値で溶断などの操作を行うこともできる.
  • AtomicBooleanは、初期化中のマルチスレッド環境での同時セキュリティの問題を解決します.

  • 四、まとめ
  • volatile原語を用いて、スレッド間のデータが可視(共有)であることを保証する.
  • 2は、CAS操作を採用し、メモリからデータを読み出して+1後の結果をCAS操作し、成功すれば結果を返し、成功するまでcompareAndSetはJNIを利用してCPUコマンドの操作を完了する.
  • ABA問題:例えばスレッドoneがメモリ位置VからAを取り出すと、別のスレッドtwoもメモリからAを取り出し、twoがいくつかの操作を行ってBになり、twoがV位置のデータをAにし、スレッドoneがCAS操作を行うとメモリにAが残っていることがわかり、one操作に成功します.スレッドoneのCAS操作は成功したが,このプロセスに問題がないわけではない.チェーンテーブルのヘッダが2回変化した後に元の値に戻った場合、チェーンテーブルが変化していないわけではありません.ABAの問題を解決するには、変数値を更新するときに1つの変数値だけを更新するのではなく、2つの値を更新する必要があります.それぞれ変数値とバージョン番号
  • です.
  • synchronizedのコストは比較的高く、ロックオブジェクトを取得する必要があり、ロックオブジェクトを解放するには原子変数を使用してマルチスレッドの優先度の逆転とデッドロックの発生を回避し、高同時処理での性能を向上させることができる.

  • 私の微信公衆番号:アーキテクチャ真経(id:gentoo 666)、Java乾物、高同時プログラミング、人気技術チュートリアル、マイクロサービスと分布式技術、アーキテクチャ設計、ブロックチェーン技術、人工知能、ビッグデータ、Java面接問題、最前線の人気情報などを共有します.毎日更新します!