概述
CountDownLatch是一个同步工具类,它允许一个或多个线程一直等待,直到其他线程的操作执行完后再执行。它的实现原理通过一个计数器来实现的,计数器的初始值为线程的数量。每当一个线程完成了自己的任务后,计数器的值就会减1。当计数器值到达0时,它表示所有的线程已经完成了任务,然后在闭锁上等待的线程就可以恢复执行任务。
CountDownLatch类位于java.util.concurrent包下,CountDownLatch提供1个有参构造器:
public CountDownLatch(int count)
#count 表示闭锁线程需要等待的线程数,一旦被初始化不能修改。
CountDownLatch有两个重要的方法await和countDown方法。
-
await
该方法用于阻塞主线程,直到其他线程将countdown减为0。public void await() throws InterruptedException public boolean await(long timeout, TimeUnit unit)
版本2提供了超时时间,当超时时间一到,主线程会继续往下执行。
- countDown
其它线程必须完成任务后必须调用countDown方法使countdown的计数减。
代码示例
举一个例子:
在主线程中启动5个子线程来执行20个任务,只有等任务全部完成后,主线程才能继续往下执行。
public class CountDownLatchTest {
private static final int threadcount = 5;
private static final CountDownLatch countdown = new CountDownLatch(threadcount);
public static void main(String[] args) throws InterruptedException {
ExecutorService executor = Executors.newCachedThreadPool();
for (int i = 0; i < threadcount ; ++i) {
executor.submit(new CountDownThread(countdown, i));
}
countdown.await();
System.out.println("5个子任务执行完毕,主线程继续执行");
executor.shutdownNow();
}
}
class CountDownThread implements Runnable {
private CountDownLatch countdown;
private int i;
public CountDownThread(CountDownLatch countdown, int i) {
this.countdown = countdown;
this.i = i;
}
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("任务" + i + "执行完毕");
countdown.countDown();
}
}
运行结果:
任务0执行完毕
任务1执行完毕
任务2执行完毕
任务4执行完毕
任务3执行完毕
5个子任务执行完毕,主线程继续执行
考虑下面的场景:
在主线程中启动5个子线程来执行20个任务,主线程不会等到所有的线程执行完,当过了超时时间它就会继续往下执行。
可以在上面await()处加上超时时间。
countdown.await(500, TimeUnit.MILLISECONDS);
执行结果:
5个子任务执行完毕,主线程继续执行
任务4执行完毕
任务1执行完毕
任务2执行完毕
任务3执行完毕
任务0执行完毕
对比
下面两段话是从源代码注释中摘录出来的:
CountDownLatch: A synchronization aid that allows one or more threads
to wait until a set of operations being performed in other threads completes.
CyclicBarrier: A synchronization aid that allows a set of threads to all wait for each other to reach a common barrier point.
从设计目的上来看:
- CountDownLatch:一个或者多个线程,等待其他多个线程完成某件事情之后才能执行。
- CyclicBarrier:多个线程互相等待,直到到达同一个同步点,再继续一起执行。
从使用上来看:
- CountDownLatch:一般当做计数器使用,只能使用一次。
- CyclicBarrier:CyclicBarrier的计数器提供reset功能,可以多次使用。