**简要描述**
CountDownLatch,允许一个或多个线程中的一些操作同步等待直到其他线程的一些操作执行完。
{@code CountDownLatch}方法以给定count参数实例化对象。{@link #await await}方法将会一直阻塞线程,直到参数实例变量count变量变为
0(每调用一次{@link #countDown}方法,count减1)。当实例变量count变量变为0后,所有等待的线程将会释放并且{@link #await await}方法后面
的调用将会立即返回。但是这是一次性的,即count不能被重置。如果你想使用可重置count的版本请考虑使用{@link CyclicBarrier}。
简单讲就是countDown()方法被调用count次后,await()方法后的代码才会继续执行。
public class TestCountDownLatch {
public static void main(String[] args) throws InterruptedException {
final CountDownLatch latch = new CountDownLatch(3);
System.out.println(Thread.currentThread().getName() + "执行开始!");
for(int i = 0; i < latch.getCount(); i++){
new Thread(){
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "执行!");
latch.countDown();
}
}.start();
}
latch.await();
System.out.println(Thread.currentThread().getName() + "执行完毕!");
}
}
上面的"main执行完毕!"这行输出,肯定是最后打印,由于系统调用线程的随机性可能结果如下:
main执行开始!
Thread-0执行!
Thread-1执行!
Thread-2执行!
main执行完毕!
如果注释掉latch.await(),则会由于系统调用线程的随机性,输出结果也会出现随机性。可能结果如下:
main执行开始!
Thread-0执行!
main执行完毕!
Thread-1执行!
Thread-2执行!
所以我们可以从上面的示例可以看出。虽然线程的执行是随机的,但是我们可以通过CountDownLatch这个类来控制线程执行的顺序。
下面是CountDownLatch JDK8源码中给出的示例:
示例: 这里有两个类,在其中一组工作线程使用两个倒计时门闩:
第一个是一个开始信号,会一直等待直到driver准备好让他们执行,才会执行
第二个是完成信号,它允许driver一直等待直到所有的workers全部完成。
* 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
* 完成后,协调线程将会通过等待。当线程必须以这种倒数方式重复执行时,请使用{@link 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() {
* try {
* doWork(i);
* doneSignal.countDown();
* } catch (InterruptedException ex) {} // return;
* }
*
* void doWork() { ... }
* }}
*
CountDownLatch的使用
最新推荐文章于 2022-11-27 20:50:29 发布