Module java.base

Class CountDownLatch

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

public class CountDownLatch extends Object
一个同步辅助工具,允许一个或多个线程等待,直到其他线程中正在执行的一组操作完成。

CountDownLatch 使用给定的计数进行初始化。 await 方法会阻塞,直到由于调用 countDown() 方法而使当前计数达到零,此后所有等待的线程都会被释放,并且任何后续调用 await() 的方法都会立即返回。这是一个一次性现象 -- 计数无法重置。如果需要一个可以重置计数的版本,请考虑使用 CyclicBarrier

CountDownLatch 是一个多功能的同步工具,可以用于多种目的。使用计数为一的 CountDownLatch 可以作为一个简单的开关:所有调用 await() 的线程都会在开关处等待,直到被调用 countDown() 的线程打开。使用初始化为 NCountDownLatch 可以使一个线程等待,直到 N 个线程完成某个动作,或某个动作已经完成了 N 次。

CountDownLatch 的一个有用属性是,调用 countDown 的线程不需要等待计数达到零才能继续,它只是阻止任何线程在所有线程都通过 await() 之前继续进行。

示例用法: 这里是一对类,其中一组工作线程使用了两个倒计时闩:

  • 第一个是一个启动信号,防止任何工作线程在驱动程序准备好让它们继续之前进行;
  • 第二个是一个完成信号,允许驱动程序等待直到所有工作线程都完成。
 
 class Driver { // ...
   void main() throws InterruptedException {
     CountDownLatch startSignal = new CountDownLatch(1);
     CountDownLatch doneSignal = new CountDownLatch(N);

     for (int i = 0; i < N; ++i) // 创建并启动线程
       new Thread(new Worker(startSignal, doneSignal)).start();

     doSomethingElse();            // 先不要运行
     startSignal.countDown();      // 让所有线程继续
     doSomethingElse();
     doneSignal.await();           // 等待所有线程完成
   }
 }

 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) {} // 返回;
   }

   void doWork() { ... }
 }

另一个典型的用法是将问题分解为 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) // 创建并启动线程
       e.execute(new WorkerRunnable(doneSignal, i));

     doneSignal.await();           // 等待所有线程完成
   }
 }

 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() 成功返回之后的操作。

自 JDK 版本:
1.5
  • Constructor Summary

    Constructors
    Constructor
    Description
    CountDownLatch(int count)
    构造一个使用给定计数初始化的 CountDownLatch
  • Method Summary

    Modifier and Type
    Method
    Description
    void
    await()
    使当前线程等待,直到闩计数减为零,除非线程被中断
    boolean
    await(long timeout, TimeUnit unit)
    使当前线程等待,直到闩计数减为零,除非线程被中断,或者经过了指定的等待时间。
    void
    减少闩的计数,如果计数达到零,则释放所有等待的线程。
    long
    返回当前计数。
    返回标识此闩及其状态的字符串。

    Methods declared in class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
  • Constructor Details

    • CountDownLatch

      public CountDownLatch(int count)
      构造一个使用给定计数初始化的 CountDownLatch
      参数:
      count - 在线程可以通过 await() 之前必须调用 countDown() 的次数
      抛出:
      IllegalArgumentException - 如果 count 为负数
  • Method Details

    • await

      public void await() throws InterruptedException
      使当前线程等待,直到闩计数减为零,除非线程被中断

      如果当前计数为零,则此方法立即返回。

      如果当前计数大于零,则当前线程会因为线程调度目的而被禁用,并处于休眠状态,直到发生以下两种情况之一:

      • 计数因为调用 countDown() 方法而达到零;或
      • 其他线程中断了当前线程。

      如果当前线程:

      • 在进入此方法时设置了中断状态;或
      • 在等待时被中断
      那么将抛出InterruptedException,并清除当前线程的中断状态。
      抛出:
      InterruptedException - 如果当前线程在等待时被中断
    • await

      public boolean await(long timeout, TimeUnit unit) throws InterruptedException
      使当前线程等待,直到闩计数减为零,除非线程被中断,或者经过了指定的等待时间。

      如果当前计数为零,则此方法将立即返回值为 true

      如果当前计数大于零,则当前线程会因为线程调度目的而被禁用,并处于休眠状态,直到发生以下三种情况之一:

      • 计数因为调用 countDown() 方法而达到零;或
      • 其他线程中断了当前线程;或
      • 经过了指定的等待时间。

      如果计数达到零,则该方法将返回值为 true

      如果当前线程:

      • 在进入此方法时设置了中断状态;或
      • 在等待时被中断
      那么将抛出InterruptedException,并清除当前线程的中断状态。

      如果指定的等待时间经过,则返回值为 false。如果时间小于或等于零,则该方法将根本不等待。

      参数:
      timeout - 最长等待时间
      unit - timeout 参数的时间单位
      返回:
      如果计数达到零则返回 true,如果等待时间在计数达到零之前已过则返回 false
      抛出:
      InterruptedException - 如果当前线程在等待时被中断
    • countDown

      public void countDown()
      减少闩的计数,如果计数达到零,则释放所有等待的线程。

      如果当前计数大于零,则将其递减。如果新计数为零,则所有等待的线程都将重新启用以进行线程调度。

      如果当前计数等于零,则不会发生任何事情。

    • getCount

      public long getCount()
      返回当前计数。

      此方法通常用于调试和测试目的。

      返回:
      当前计数
    • toString

      public String toString()
      返回标识此闩及其状态的字符串。状态在括号中包括字符串 "Count =" 后跟当前计数。
      覆盖:
      toString 在类 Object
      返回:
      标识此闩及其状态的字符串