CountDownLatch
の場合、他のスレッドはリーグ オブ レジェンドなどのゲーム プレーヤーであり、メイン スレッドはゲームの開始を制御するスレッド。すべてのプレイヤーの準備が整う前に、メインスレッドは待機状態になります。これは、ゲームを開始できないことを意味します。すべてのプレイヤーの準備が整うと、次のアクション実行者がメインスレッドとなり、ゲームが開始されます。
CyclicBarrier について、会社が全従業員にチームビルディング活動を実施させたいとします。活動内容は 3 つの障害物を登るというもので、各人が障害物を登るのにかかる時間は異なります。ただし、会社では、全員が次の障害物を乗り越え始める前に、現在の障害物を乗り越えることを要求しています。つまり、全員が最初の障害物を乗り越えた後、2 番目の障害物を乗り越え始めます。たとえて言えば、すべての従業員は「他のスレッド」です。全員がすべての障害を乗り越えると、プログラムは終了します。メインスレッドはずっと前に終了している可能性があるため、ここではメインスレッドについて心配する必要はありません。
CyclicBarrier は、どの親クラスを継承するか、どの親インターフェイスを実装するかを示しません。すべての AQS およびリエントラント ロックは、継承は組み合わせによって実現されます。
public class CyclicBarrier {} ``` ### 类的内部类 CyclicBarrier类存在一个内部类Generation,每一次使用的CycBarrier可以当成Generation的实例,其源代码如下 ```java private static class Generation { boolean broken = false; }
説明: Generation クラスには、現在のバリアが損傷しているかどうかを示すために使用される属性 Broker があります。
public class CyclicBarrier { /** The lock for guarding barrier entry */ // 可重入锁 private final ReentrantLock lock = new ReentrantLock(); /** Condition to wait on until tripped */ // 条件队列 private final Condition trip = lock.newCondition(); /** The number of parties */ // 参与的线程数量 private final int parties; /* The command to run when tripped */ // 由最后一个进入 barrier 的线程执行的操作 private final Runnable barrierCommand; /** The current generation */ // 当前代 private Generation generation = new Generation(); // 正在等待进入屏障的线程数量 private int count; }
説明: この属性には ReentrantLock オブジェクトと Condition オブジェクトがあり、Condition オブジェクトは AQS に基づいているため、最終的な分析では、最下層は引き続き AQS によってサポートされています。
CyclicBarrier(int, Runnable) 型コンストラクター
public CyclicBarrier(int parties, Runnable barrierAction) { // 参与的线程数量小于等于0,抛出异常 if (parties <= 0) throw new IllegalArgumentException(); // 设置parties this.parties = parties; // 设置count this.count = parties; // 设置barrierCommand this.barrierCommand = barrierAction; }
説明: Thisコンストラクターでは、CyclicBarrier に関連付けられたスレッドの数を指定でき、すべてのスレッドがバリアに入った後の実行アクションを指定できます。実行アクションは、バリアを実行する最後のスレッドによって実行されます。
CyclicBarrier(int) 型コンストラクター
public CyclicBarrier(int parties) { // 调用含有两个参数的构造函数 this(parties, null); }
説明: このコンストラクターは、CyclicBarrier に関連付けられた関数のみを実行します。スレッドの数に応じて、実行アクションは設定されません。
この関数は CyclicBarrier クラスのコア関数であり、CyclicBarrier クラスが提供する await 関数は最下層の doawait 関数を呼び出します。
ソース コードは次のとおりです。
private int dowait(boolean timed, long nanos) throws InterruptedException, BrokenBarrierException, TimeoutException { // 保存当前锁 final ReentrantLock lock = this.lock; // 锁定 lock.lock(); try { // 保存当前代 final Generation g = generation; if (g.broken) // 屏障被破坏,抛出异常 throw new BrokenBarrierException(); if (Thread.interrupted()) { // 线程被中断 // 损坏当前屏障,并且唤醒所有的线程,只有拥有锁的时候才会调用 breakBarrier(); // 抛出异常 throw new InterruptedException(); } // 减少正在等待进入屏障的线程数量 int index = --count; if (index == 0) { // 正在等待进入屏障的线程数量为0,所有线程都已经进入 // 运行的动作标识 boolean ranAction = false; try { // 保存运行动作 final Runnable command = barrierCommand; if (command != null) // 动作不为空 // 运行 command.run(); // 设置ranAction状态 ranAction = true; // 进入下一代 nextGeneration(); return 0; } finally { if (!ranAction) // 没有运行的动作 // 损坏当前屏障 breakBarrier(); } } // loop until tripped, broken, interrupted, or timed out // 无限循环 for (;;) { try { if (!timed) // 没有设置等待时间 // 等待 trip.await(); else if (nanos > 0L) // 设置了等待时间,并且等待时间大于0 // 等待指定时长 nanos = trip.awaitNanos(nanos); } catch (InterruptedException ie) { if (g == generation && ! g.broken) { // 等于当前代并且屏障没有被损坏 // 损坏当前屏障 breakBarrier(); // 抛出异常 throw ie; } else { // 不等于当前带后者是屏障被损坏 // We're about to finish waiting even if we had not // been interrupted, so this interrupt is deemed to // "belong" to subsequent execution. // 中断当前线程 Thread.currentThread().interrupt(); } } if (g.broken) // 屏障被损坏,抛出异常 throw new BrokenBarrierException(); if (g != generation) // 不等于当前代 // 返回索引 return index; if (timed && nanos <= 0L) { // 设置了等待时间,并且等待时间小于0 // 损坏屏障 breakBarrier(); // 抛出异常 throw new TimeoutException(); } } } finally { // 释放锁 lock.unlock(); } }
この関数は、すべてのスレッドがバリアに入った後に呼び出されます。次のバージョンが生成され、すべてのスレッドがバリアに再度入ることができます。
ソース コードは次のとおりです:
private void nextGeneration() { // signal completion of last generation // 唤醒所有线程 trip.signalAll(); // set up next generation // 恢复正在等待进入屏障的线程数量 count = parties; // 新生一代 generation = new Generation(); }
この関数では、signalAll メソッドAQS が呼び出され、待機中のすべてのスレッドが起動されます。すべてのスレッドがこの状態を待っている場合は、すべてのスレッドを起動します。
ソースコードは次のとおりです:
public final void signalAll() { if (!isHeldExclusively()) // 不被当前线程独占,抛出异常 throw new IllegalMonitorStateException(); // 保存condition队列头节点 Node first = firstWaiter; if (first != null) // 头节点不为空 // 唤醒所有等待线程 doSignalAll(first); }
以上がJava での CyclicBarrier ソース コード分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。