JUC解析-ATomic

6514 ワード

紹介する
パス:java.util.concurrent.atomic機能:javaに含まれる基本タイプ、参照タイプ、配列などのクラスを含むいくつかの原子操作を提供します.
  • AtomicBoolean/ATomicIntegerなどの基本タイプの原子操作
  • AtomicIntegerArrayなどのいくつかの基本型配列の原子操作
  • AtomicIntegerFieldUpdaterなどのオブジェクトメンバーに対する原子操作
  • AtomicStampedReferenceなどCASにおけるABA問題を解決するために導入されたクラスの原子操作は,ここでは単純に一般クラスとして扱うことができる.

  • Unsafeクラス
    パス:sun.misc.Unsafe紹介:Unsafeは、Java言語の表現能力を実質的に拡張し、より上位層(Java層)コードでより下位層(C層)で実現するコアライブラリ機能を実現するのに便利です.これらの機能には、裸メモリの申請/解放/アクセス、低層ハードウェアのatomic/volatileサポート、未初期化オブジェクトの作成などが含まれます.従来の設計は標準ライブラリでしか使用されていないが、一般的にはjvmを介してメモリを直接操作することで効率的な効果を得ることができ、unsafeが提供するインタフェースを原子操作として使用することができ、アプリケーションでの使用は推奨されていない.
    AtomicBoolean関連原子類
    このクラスは、主に次のような基本的なタイプの原子操作を提供します.
  • get/setなどの基本的な操作、javaのほとんどの基本的なタイプに対する付与値は原子操作
  • である.
  • compareAndSetタイプの操作は、主にunsafeを呼び出すことによって行われる.compareAndSet実装
  • decrementAndGetなどのタイプの操作で、この操作はspinlock方式によって実現され、このサイクルはcompareAndSetが成功するまで実行され、コード:
  • for (;;) {
        int current = get();
            int next = current - 1;
            if (compareAndSet(current, next))
                return next;
        }
    

    クラスには2つの迷った方法がありますLazySetとweakCompareAndSet、簡単な紹介の下で、
  • LazySetは原子性を保証することができるが、マルチスレッド環境では共有変数の修正は他のスレッドに対して直ちに
  • が見えることを保証することはできない.
  • weakCompareAndSetとcomparareAndSetの具体的な実装は同じですが、ドキュメントから前者が2つ異なることがわかります.
  • 虚偽の失敗が発生する可能性があります.個人的にはcompareAndSetが失敗しないというわけではありません.この関数については失敗したときに再試行することができますが、前者は直接投げ出します(具体的な検証はありません.具体的な原理を知っている人がいれば、批判を歓迎します).
  • は、スレッドがweakCompareAndSetによって修正する原子変数を見た場合、その変数の修正がweakCompareAndSetによって操作される前に、これが特定のJMMモデルに関連するとしても、他の変数の修正を見ることを要求する.

  • AtomicIntegerArray
    このタイプのクラスは主に1つのT[]array配列に原子の操作を提供し、ここでTは具体的なarrayタイプである.原理:ArraysはJavaの他のオブジェクトと同様に、実際のデータの前に格納されているオブジェクトヘッダがあります.このヘッドの長さはunsafe.ArrayBaseOffset(T[].class)メソッドは,ここでTが配列要素のタイプであることを取得する.配列要素のサイズはunsafe.ArrayIndexScale(T[].class)メソッドが取得した.つまり、タイプTのN番目の要素にアクセスするには、オフセットoffsetはarrayOffset+N*arrayScaleであるべきで、Array関連の原子操作方法ではCASによって特定のメモリアドレスのタイプデータを操作し、その他の操作は上で紹介したのと似ており、具体的には関連するソースコードを参照することができる.
    AtomicIntegerFieldUpdater
    このタイプは主に反射とunsafeによるものである.ObjectFieldOffset形式でクラスの特定メンバー変数のアドレスを取得し、CAS方式で特定位置のメンバー変数に対して原子操作を行い、具体的な実装は内部クラスAtomicIntegerFieldUpdaterImplで実装され、AtomicIntegerFieldUpdaterで抽象的なメンバーメソッドが提供され、具体的な実装クラスにはいくつかのタイプの検証も含まれている.具体的な実装は、関連するソースコードを参照することができる.
    AtomicMarkableReference
    特定のデータ・メンバー・タイプに対して原子の操作を行います.特定のデータ・タイプは
    private static class Pair<T> {  
        final T reference;  
        final boolean mark;  
        private Pair(T reference, boolean mark) {  
            this.reference = reference;  
            this.mark = mark;  
        }  
        static  Pair of(T reference, boolean mark) {  
            return new Pair(reference, mark);  
        }  
    }  
    

    原理:前のタイプと似ていてunsafe.getFieldOffsetは、メンバー変数のoffsetを取得し、CASを介してoffsetメモリアドレスを原子操作します.compareAndSetのようなインタフェースとは異なり、referenceとmarkが等しい場合にのみ変更されます.具体的には、次のようになります.
        public boolean compareAndSet(V  expectedReference,
                                     V  newReference,
                                     boolean expectedMark,
                                     boolean newMark) {
            Pair current = pair;
            return
                expectedReference == current.reference &&
                expectedMark == current.mark &&
                ((newReference == current.reference &&
                  newMark == current.mark) ||
                 casPair(current, Pair.of(newReference, newMark)));
        }
    

    その他の実装方法は類似しており、具体的にはソースコードを参照する
    AtomicStampedReferenceクラス
    このクラスで処理されるデータ型はAtomicMarkableReferenceクラスと似ています
      private static class Pair<T> {
            final T reference;
            final int stamp;
            private Pair(T reference, int stamp) {
                this.reference = reference;
                this.stamp = stamp;
            }
            static  Pair of(T reference, int stamp) {
                return new Pair(reference, stamp);
            }
        }
    

    いずれも参照を含むメンバーであり、AtomicMarkableReferenceはbooleanタイプのメンバーを含み、AtomicStampedReferenceはintタイプのメンバーを含み、他の具体的な実装は類似している.AtomicStampedReferenceとAtomicMarkableReferenceクラスは主にABAの問題を解決するために用いられ、1つのグローバル変数Aに対して、初期状態スレッド1はA(1)状態を見て、後のスレッド2はA(2)状態に変更して、後のスレッド2はまたA(1)状態に還元して、このとき、正常な状態のCASでは、A(1)->A(2)->A(1)の変化を経たことは発見できないが、この2つのクラスによってこの問題を解決することができる.