Java CountDownLatch class is part of Concurrency API. It allows us to create a synchronization, where a thread waits until the count down is 0. It’s useful when we want a thread to wait on a finite number of other threads to finish processing.
Java CountDownLatch类是Concurrency API的一部分。 它允许我们创建一个同步,其中一个线程等待直到倒数为0。当我们希望一个线程在有限数量的其他线程上等待完成处理时,这很有用。
CountDownLatch如何工作? (How Does CountDownLatch Works?)
- The CountDownLatch instance is created with a given count. 使用给定的计数创建CountDownLatch实例。
- When a thread calls CountDownLatch await() method, it waits until the count is 0. 当线程调用CountDownLatch await()方法时,它将等待直到计数为0。
- It’s the responsibility of the other threads to call CountDownLatch countDown() method, when they are done. Every call to countDown() method reduces the count value by 1. 完成后,其他线程有责任调用CountDownLatch countDown()方法。 每次调用countDown()方法都会使计数值减少1。
- When all the other threads have called the countDown() method, the count becomes 0 and the threads waiting because of await(), starts their execution. 当所有其他线程都调用countDown()方法时,计数变为0,并且由于await()而等待的线程将开始执行。
- The value of count can’t be reset, so once a CountDownLatch work is finished, we can’t reuse the same instance. Any further calls to await() will not cause any blocking of the thread. count的值无法重置,因此一旦CountDownLatch工作完成,我们将无法重用同一实例。 进一步调用await()将不会导致线程阻塞。
Java CountDownLatch示例 (Java CountDownLatch Example)
Let’s look at a simple example of CountDownLatch in a multi-threaded application.
让我们来看一个多线程应用程序中CountDownLatch的简单示例。
package com.journaldev.concurrency;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
public class CountDownLatchExample {
public static void main(String[] args) {
CountDownLatch latch = new CountDownLatch(3);
Random random = new Random();
WorkerThread wt1 = new WorkerThread(latch, random.nextInt(5000));
WorkerThread wt2 = new WorkerThread(latch, random.nextInt(5000));
WorkerThread wt3 = new WorkerThread(latch, random.nextInt(5000));
new Thread(wt1, "WT-11").start();
new Thread(wt2, "WT-22").start();
new Thread(wt3, "WT-33").start();
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Finishing the Main Method");
}
}
class WorkerThread implements Runnable {
private CountDownLatch latch;
private int delay;
public WorkerThread(CountDownLatch latch, int delay) {
this.latch = latch;
this.delay = delay;
}
@Override
public void run() {
String name = Thread.currentThread().getName();
int delay = this.delay;
System.out.println(name + " sleeping for " + delay + " milliseconds.");
try {
Thread.sleep(delay);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.latch.countDown();
System.out.println(name + " finished");
}
}
- We have 3 worker threads and we want our main thread to wait until all of them are finished. So we initialize the CountDownLatch with count 3. 我们有3个工作线程,我们希望我们的主线程等待,直到全部完成。 因此,我们使用count 3初始化CountDownLatch。
- In the worker thread, we are calling countDown() method on the CountDownLatch instance. So, when all the 3 worker threads are done with their processing, the count will become 0 and the main thread waiting because of await() will start its execution. 在工作线程中,我们在CountDownLatch实例上调用countDown()方法。 因此,当所有3个工作线程都完成处理后,计数将变为0,并且由于await()而正在等待的主线程将开始执行。
- The main thread is blocked because of CountDownLatch await() call. As soon as the count becomes 0, it starts executing. 主线程因CountDownLatch await()调用而被阻塞。 一旦计数变为0,它将开始执行。
- We make sure that all the worker threads are executed before we finish the main thread, with the help of CountDownLatch synchronization mechanism. 在CountDownLatch同步机制的帮助下,我们确保在完成主线程之前执行所有辅助线程。
A possible output of the above program would be as follows:
上述程序的可能输出如下:
WT-33 sleeping for 2962 milliseconds.
WT-22 sleeping for 3874 milliseconds.
WT-11 sleeping for 1746 milliseconds.
WT-11 finished
WT-33 finished
WT-22 finished
Finishing the Main Method
CountDownLatch await() (CountDownLatch await())
There are two version of await() method.
有两种版本的await()方法。
- await(): waits indefinitely for the count to become 0, unless the thread is interrupted. await():无限期地等待计数变为0,除非线程被中断。
- await(long timeout, TimeUnit unit): waits for the count to become 0 with the given timeout value. If the timeout occurs, the method stops blocking and returns false. await(长超时,TimeUnit单位):使用给定的超时值等待计数变为0。 如果发生超时,则该方法停止阻塞并返回false。
CountDownLatch与CyclicBarrier (CountDownLatch vs CyclicBarrier)
- The CountDownLatch provides a mechanism to wait for the count to become 0 whereas CyclicBarrier provides a mechanism to create a common barrier “count” that is reached by every thread await() calls. CountDownLatch提供了一种机制来等待计数变为0,而CyclicBarrier提供了一种机制来创建每个线程await()调用都会到达的公共屏障“计数”。
- The CountDownLatch operations are irreversible, once the count is 0, any further calls to await() won’t block the thread. As the name CyclicBarrier suggests, it’s cyclic in nature and the barrier is reused again after the waiting threads are released. CountDownLatch操作是不可逆的,一旦计数为0,对await()的任何进一步调用都不会阻塞线程。 就像CyclicBarrier所暗示的那样,它本质上是循环的,并且在释放等待线程之后,屏障会再次使用。
- CountDownLatch is useful when we want to wait on a specific set of threads to execute. The CyclicBarrier is useful when we have a number of threads and we want to wait only when a certain number of them are executed. 当我们要等待一组特定的线程执行时,CountDownLatch很有用。 当我们有多个线程并且我们只想在执行一定数量的线程时才等待时,CyclicBarrier很有用。