CountDownLatchからAQSへ

前に書く

AQSを学習するためのCountDownLatchソースコード

デモ

public static void main(String[] args) throws InterruptedException {
    
    
    CountDownLatch countDownLatch = new CountDownLatch(2);
    new Thread(()->{
    
    
       try {
    
    
           System.out.println("线程1执行");
           Thread.sleep(5000L);
       } catch (InterruptedException e) {
    
    
           e.printStackTrace();
       } finally {
    
    
           countDownLatch.countDown();
       }

    }).start();

     new Thread(()->{
    
    
        try {
    
    
            System.out.println("线程2执行");
            Thread.sleep(2000L);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            countDownLatch.countDown();
        }

     }).start();
     countDownLatch.await();
     System.out.println("两个线程都执行完执行此段代码");
}
  • メインスレッド、スレッド1、スレッド2が並列実行を開始
  • メインスレッドがcountDownLatch.await()待機に遭遇します
  • 2秒後、スレッド1の実行が完了し、countDownLatch.countDown()が実行されます。
  • 5秒後、スレッド2の実行が完了し、countDownLatch.countDown()が実行されます。
  • 2回のカウントダウンの後、メインスレッドはブロックが通過するのを待ちます
  • 回数は工法の価値によって異なります

ソースコード分析

工法

状態値を2に設定し、他のロジックはありません

countDownLatch.await()

最終的なコール

public final void acquireSharedInterruptibly(int arg)
       throws InterruptedException {
    
    
    if (Thread.interrupted())
        throw new InterruptedException();
     //尝试获取锁
    if (tryAcquireShared(arg) < 0)
        doAcquireSharedInterruptibly(arg);
}

tryAcquireShared

protected int tryAcquireShared(int acquires) {
    
    
    return (getState() == 0) ? 1 : -1;
}
  • 状態値を取得します。0に等しい場合は1を返し、0に等しくない場合は-1を返します。
  • 状態が0に等しい場合、ダウンを続けることができることがわかっています。例としてのデモによると、初期状態値は2であり、0に等しくありません(スレッド1とスレッド2はcountDownを実行しませんでした)。 -1を返します

続けてdoAcquireSharedInterruptibly

private void doAcquireSharedInterruptibly(int arg)
    throws InterruptedException {
    
    
    final Node node = addWaiter(Node.SHARED);
    boolean failed = true;
    try {
    
    
        for (;;) {
    
    
            final Node p = node.predecessor();
            if (p == head) {
    
    
                int r = tryAcquireShared(arg);
                if (r >= 0) {
    
    
                    setHeadAndPropagate(node, r);
                    p.next = null; // help GC
                    failed = false;
                    return;
                }
            }
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                throw new InterruptedException();
        }
    } finally {
    
    
        if (failed)
            cancelAcquire(node);
    }
}

既視感はありますか?これがaqsの方法です。この方法の論理については前に説明しました。つまり、メインスレッドがclhキューに追加され、共有状態に設定されてから、それがヘッドの次のノードであるかどうかを引き続き判別し、共有ロックの取得を試みます。正常に返されます。失敗し、現在のスレッドをブロックします

  • tryAcquireSharedは前のものとは異なります。これはcountdownlatchのサブクラス実装です。状態が0かどうかを判断するだけで済みます。状態が0の場合のみ、スレッドはダウンし続けます。
  • ここでメインスレッドキューがブロックされていることを覚えています
  • キューメンバーヘッド->メインスレッドここでは1つのメインスレッドのみがブロックされます
protected int tryAcquireShared(int acquires) {
    
    
     return (getState() == 0) ? 1 : -1;
 }

countDownLatch.countDown()

最後の呼び出し、またはaqsのメソッド

public final boolean releaseShared(int arg) {
    
    
     //尝试释放锁
     if (tryReleaseShared(arg)) {
    
    
         //释放成功后唤醒线程
         doReleaseShared();
         return true;
     }
     return false;
 }

CountDownLatchサブクラスのTryReleaseShared実装

protected boolean tryReleaseShared(int releases) {
    
    
    for (;;) {
    
    
        int c = getState();
        if (c == 0)
            return false;
        int nextc = c-1;
        if (compareAndSetState(c, nextc))
            return nextc == 0;
    }
}
  • 無限ループとcasは、マルチスレッドの問題を考慮に入れることです
  • 最初に状態を取得します。デモの例によると、状態は2です。
  • 状態が0の場合、ロックは解放されているため、再度解放する必要はありません。
  • casを使用して2を1に変更します。マルチスレッド実行の場合、失敗したスレッドは次のループを実行し、1を0に設定します。
  • 最後に、状態が0に設定されているスレッドはtrueを返します

doReleaseShared

または、共有ロックをウェイクアップするaqsメソッドについては、セマフォのソースコード分析を参照してください。ウェイクアップ後、メインスレッドはブロックされて解放されます。次のループが実行された後、状態がすでに0の場合、ビジネスコードが実行されます。

ここに画像の説明を挿入
上記はCountDownLatchの一般的なソースコード分析です。間違いがあれば、批判や訂正を歓迎します。

おすすめ

転載: blog.csdn.net/qq_37904966/article/details/113481253