モジュール java.base
パッケージ java.util.concurrent

クラスCountDownLatch

java.lang.Object
java.util.concurrent.CountDownLatch

public class CountDownLatch extends Object
ほかのスレッドで実行中の操作セットが完了するまで、1つ以上のスレッドを待機可能にする同期化支援機能です。

CountDownLatchは、指定されたカウントで初期化されます。 awaitメソッドは、countDown()メソッドの呼出しによって現在のカウントがゼロに達するまでブロックします。その後、待機中のすべてのスレッドが解放され、以降のawaitのすべての呼出しがただちに復帰します。 これは単発的な現象であり、カウントをリセットすることはできません。 カウントをリセットするバージョンが必要な場合は、CyclicBarrierの使用を検討してください。

CountDownLatchはさまざまな目的に使用できる柔軟性の高い同期ツールです。 カウント1で初期化されたCountDownLatchは、単純なオン/オフのラッチ、つまりゲートとして機能します。awaitを呼び出すスレッドはすべて、countDown()を呼び出すスレッドによって開かれるまでゲートで待機します。 Nに初期化されたCountDownLatchを使用すると、N個のスレッドが特定のアクションを完了するか、または特定のアクションがN回完了するまで、あるスレッドを待機させることができます。

CountDownLatchの有効な特性の1つに、countDownを呼び出すスレッドが、カウントがゼロに達するまで処理を待機する必要がないことです。これは単純に、すべてのスレッドが通過するまで、どのスレッドもawaitを通過できないようにします。

使用例: 次に示すクラスのペアでは、ワーカー・スレッドのグループが次の2つのカウントダウン・ラッチを使用します。

  • 最初のクラスは、ドライバの進行準備ができるまで、ワーカーが先に進むのを防ぐ開始信号である。
  • 2番目のクラスは、すべてのワーカーが完了するまでドライバの待機を許可する完了信号である。
 
 class Driver { // ...
   void main() throws InterruptedException {
     CountDownLatch startSignal = new CountDownLatch(1);
     CountDownLatch doneSignal = new CountDownLatch(N);

     for (int i = 0; i < N; ++i) // create and start threads
       new Thread(new Worker(startSignal, doneSignal)).start();

     doSomethingElse();            // don't let run yet
     startSignal.countDown();      // let all threads proceed
     doSomethingElse();
     doneSignal.await();           // wait for all to finish
   }
 }

 class Worker implements Runnable {
   private final CountDownLatch startSignal;
   private final CountDownLatch doneSignal;
   Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {
     this.startSignal = startSignal;
     this.doneSignal = doneSignal;
   }
   public void run() {
     try {
       startSignal.await();
       doWork();
       doneSignal.countDown();
     } catch (InterruptedException ex) {} // return;
   }

   void doWork() { ... }
 }

もう1つの標準的な使用法は、問題をN個の部分に分割し、各部を実行してラッチをカウント・ダウンするRunnableを使用して各部分を記述し、すべてのRunnableをexecutorのキューに入れる方法です。 下位部分がすべて完了すると、調整役のスレッドはawaitを抜けることができます。 スレッドがこの方法でカウント・ダウンを繰り返す必要がある場合は、代わりにCyclicBarrierを使用してください。

 
 class Driver2 { // ...
   void main() throws InterruptedException {
     CountDownLatch doneSignal = new CountDownLatch(N);
     Executor e = ...;

     for (int i = 0; i < N; ++i) // create and start threads
       e.execute(new WorkerRunnable(doneSignal, i));

     doneSignal.await();           // wait for all to finish
   }
 }

 class WorkerRunnable implements Runnable {
   private final CountDownLatch doneSignal;
   private final int i;
   WorkerRunnable(CountDownLatch doneSignal, int i) {
     this.doneSignal = doneSignal;
     this.i = i;
   }
   public void run() {
     doWork();
     doneSignal.countDown();
   }

   void doWork() { ... }
 }

メモリー整合性効果: カウントがゼロに達するまで、countDown()を呼び出す前のスレッド内のアクションは、別のスレッド内の対応するawait()からの正常な復帰に続くアクションの前に発生します。

導入されたバージョン:
1.5