CountDownLatch 使用给定的 count 进行初始化。 await 方法会阻塞,直到当前计数由于调用 countDown() 方法而变为零,之后所有等待的线程都会被释放,并且任何后续的 await 调用都会立即返回。这是一种一次性现象——无法重置计数。如果您需要重置计数的版本,请考虑使用 CyclicBarrier 。
CountDownLatch 是一种多功能同步工具,可用于多种用途。初始化为 1 的 CountDownLatch 用作简单的开/关锁存器或门:所有调用 await 的线程都在门处等待,直到它被调用 countDown() 的线程打开。初始化为 N 的 CountDownLatch 可用于使一个线程等待,直到 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) // 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() { ... }
}
另一个典型的用法是将一个问题分成 N 个部分,用一个 Runnable 来描述每个部分,该 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
-
构造方法总结
构造方法 -
方法总结
修饰符和类型方法描述voidawait()导致当前线程等待,直到锁存器倒计时到零,除非线程是 interrupted 。boolean导致当前线程等待,直到锁存器倒计时为零,除非线程为 interrupted 或指定的等待时间已过。void减少闩锁的计数,如果计数达到零,则释放所有等待的线程。longgetCount()返回当前计数。toString()返回标识此锁存器及其状态的字符串。
-
构造方法详细信息
-
CountDownLatch
public CountDownLatch(int count) 构造一个用给定计数初始化的CountDownLatch。- 参数:
count- 在线程可以通过await()之前必须调用countDown()的次数- 抛出:
IllegalArgumentException- 如果count为负
-
-
方法详情
-
await
导致当前线程等待,直到锁存器倒计时到零,除非线程是 interrupted 。如果当前计数为零,则此方法立即返回。
如果当前计数大于零,则当前线程出于线程调度目的而被禁用并处于休眠状态,直到发生以下两种情况之一:
- 由于调用了
countDown()方法,计数达到零;或者 - 一些其他线程 中断 当前线程。
如果当前线程:
- 在进入此方法时设置其中断状态;或者
- 等待时是interrupted,
InterruptedException并清除当前线程的中断状态。- 抛出:
InterruptedException- 如果当前线程在等待时被中断
- 由于调用了
-
await
导致当前线程等待,直到锁存器倒计时为零,除非线程为 interrupted 或指定的等待时间已过。如果当前计数为零,则此方法立即返回值
true。如果当前计数大于零,则当前线程出于线程调度目的而被禁用并处于休眠状态,直到发生以下三种情况之一:
- 由于调用了
countDown()方法,计数达到零;或者 - 一些其他线程中断当前线程;或者
- 指定的等待时间已过。
如果计数达到零,则该方法返回值
true。如果当前线程:
- 在进入此方法时设置其中断状态;或者
- 等待时是interrupted,
InterruptedException并清除当前线程的中断状态。如果指定的等待时间过去,则返回值
false。如果时间小于或等于零,则该方法根本不会等待。- 参数:
timeout- 最长时间等待unit-timeout参数的时间单位- 返回:
true如果计数达到零,false如果在计数达到零之前等待时间过去- 抛出:
InterruptedException- 如果当前线程在等待时被中断
- 由于调用了
-
countDown
public void countDown()减少闩锁的计数,如果计数达到零,则释放所有等待的线程。如果当前计数大于零,则递减。如果新计数为零,则重新启用所有等待线程以用于线程调度目的。
如果当前计数为零,则什么也不会发生。
-
getCount
public long getCount()返回当前计数。此方法通常用于调试和测试目的。
- 返回:
- 当前计数
-
toString
返回标识此锁存器及其状态的字符串。括号中的状态包括字符串"Count =",后跟当前计数。
-