AQS 10,000ワードのグラフィックとテキストの包括的な分析

AQS 10,000ワードのグラフィックとテキストの包括的な分析

序文

同時実行性に関して言えば、AQS(AbstractQueuedSynchronizer)いわゆるAQS抽象キュー シンクロナイザーには内部的にロック関連のメソッドが多数定義されており、よく知られている 、ReentrantLockReentrantReadWriteLockなどCountDownLatchSemaphoreすべてAQSに基づいて実装されています。

まずはAQS関連する写真を見てみましょうUML

画像

マインドマッピング:

画像

AQS実装原理

AQSvolatile int state1 つ(共有リソースを表す) とFIFOスレッド待機キューが維持されます(このキューは、マルチスレッドがリソースを求めて競合し、ブロックされたときに入力されます)。

これによりvolatile、マルチスレッドでの可視性を確保することができますstate=1現在のオブジェクトのロックが占有されている場合、他のスレッドはロックに失敗します ロックに失敗したスレッドは待ちキューに入れられ、比率が演算されFIFOますUNSAFE.park()サスペンド、ロックを取得した他のスレッドがロックを解放するのを待ってからウェイクアップされます。

他の操作は、同時変更の安全性を確保するstateために実行されます。CAS

具体的な原理を図で簡単に要約すると、次のようになります。

画像

AQSロックの多くの実装メソッドを提供します。

  • getState(): ロックのフラグ状態値を取得します。

  • setState(): ロックフラグの状態値を設定します。

  • tryAcquire(int): 排他的にロックを取得します。リソースの取得を試行し、成功した場合は true を返し、失敗した場合は false を返します。

  • tryRelease(int): 排他的にロックを解放します。リソースの解放を試行し、成功した場合は true を返し、失敗した場合は false を返します。

ここに挙げていないメソッドもまだいくつかありますが、次にReentrantLockソースコードと図面をブレークスルーポイントとして、AQS内部の実装原理を段階的に理解していきます。

ディレクトリ構造

AQSこの記事では、ソース コードを分析するために、マルチスレッドがロックを競合し、ロックを解放するシナリオをシミュレートします。

3 つのスレッド (スレッド 1、スレッド 2、およびスレッド 3) が同時にロック/ロックを解放します。

ディレクトリは次のとおりです。

  • スレッドが正常にロックされたときにAQS内部的に実装されます

  • スレッド2/3がロック失敗時のAQS待機キューのデータモデル

  • スレッド 1 がロックを解放し、スレッド 2 がロックを取得する実装原理

  • スレッドシナリオによるフェアロックの具体的な実装原則を説明する

  • スレッド シナリオを通じて、Condition 内のwait()andsignal()の実装原理を説明する

AQSここではロックとロック解除後の各スレッドの内部データ構造と実装原理を解析する図を描いていきます。

シナリオ分析

スレッド 1 は正常にロックされました

3 つのスレッドが同時にロックを取得した場合、スレッド 1 はロックの取得に成功しますが、スレッド 23 はロックの取得に失敗します。具体的な実行プロセスは次のとおりです。

画像

この時点の内部データはAQS次のとおりです。

画像

スレッド 2スレッド 3 はロックに失敗しました:

画像

図からわかるように、待機キュー内のノードはNode双方向リンク リストです。ここに の属性があり、SIGNAL真ん中Node別の属性があります。これは図には描かれていません。これについては、で説明します。詳細は後ほど。waitStatusNodenextWaiterCondition

プリエンプション ロック コードの実装を詳しく見てみましょう。

java.util.concurrent.locks.ReentrantLock .NonfairSync:
static final class NonfairSync extends Sync {

    final void lock() {
        if (compareAndSetState(0, 1))
            setExclusiveOwnerThread(Thread.currentThread());
        else
            acquire(1);
    }

    protected final boolean tryAcquire(int acquires) {
        return nonfairTryAcquire(acquires);
    }
}

ここで使用されるReentrantLock は、不公平なロックです。スレッドが入ってきて、CASロックを直接プリエンプトしようとします。プリエンプションが成功すると、state値は 1 に変更され、オブジェクトの排他ロック スレッドが現在のスレッドに設定されます。次のように:

protected final boolean compareAndSetState(int expect, int update) {
    return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}

protected final void setExclusiveOwnerThread(Thread thread) {
    exclusiveOwnerThread = thread;
}

スレッド 2 がロックを取得できませんでした

実際のシナリオに従って分析してみましょう。スレッド 1 がロックを正常に取得した後、スレッドstate1 は 1 に変更されます。スレッド 2 は、変数CASを変更すると必然的に失敗します。stateこのときAQSFIFOキュー内のデータ (先入れ先出し) は次の図のようになります。

画像

スレッド2 の実行ロジックを段階的に分解してみましょう。

java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire():

public final void acquire(int arg) {
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}

まずtryAcquire()具体的な実装を見てみましょう : java.util.concurrent.locks.ReentrantLock .nonfairTryAcquire():

final boolean nonfairTryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    int c = getState();
    if (c == 0) {
        if (compareAndSetState(0, acquires)) {
            setExclusiveOwnerThread(current);
            return true;
        }
    }
    else if (current == getExclusiveOwnerThread()) {
        int nextc = c + acquires;
        if (nextc < 0)
            throw new Error("Maximum lock count exceeded");
        setState(nextc);
        return true;
    }
    return false;
}

nonfairTryAcquire()メソッド内で最初に取得するstate値。0でない場合は、カレントオブジェクトのロックが他のスレッドに占有されていることを意味し、ロックを占有しているスレッドがカレントスレッドであるかどうかを判定する。 , 累積state値が累積されます. これがリエントラントロックの具体的な目的です.実装, 累積state値,stateロック解放時のデクリメント値.

state0 の場合は、CAS操作を実行してstate値を 1 に更新しようとします。更新が成功した場合は、現在のスレッドが正常にロックされたことを意味します。

スレッド 2 を例にとると、スレッド 1 がすでにstate1 に変更しているため、スレッド 2 はCAS変更された値では成功しませんstateロックに失敗しました。

スレッド 2は実行後に false を返しtryAcquire()addWaiter(Node.EXCLUSIVE)ロジックを実行してFIFO待機キューに自身を追加します&#x

おすすめ

転載: blog.csdn.net/mmmmm44444/article/details/131979705