CountDownLatch
CountDownLatch是一个同步辅助类,位于java.util.concurrent包中。
其作用是:在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。
闭锁可以延迟线程的进度知道其达到终止状态,闭锁可以用来确保某些活动直到其他活动都完成才继续执行:
- 确保某个计算在其需要的所有资源都被初始化之后才继续执行;
- 确保某个服务在其依赖的所有其他服务都已经启动之后才启动;
- 等待直到某个操作所有参与者都准备就绪再继续执行;
CountDownLatch的构造函数接收一个int类型的参数作为计数器,如果我们想等待N个点完成,这里就传入N。
当我么调用CountDownLatch的countDown()方法时,N就会减一,CountDownLatch的await方法会阻塞当前线程,知道N变成零。由于CountDown()方法可以用在任何地方,所以这里说的N个点,可以使N个线程,也可以是1个线程里的N个执行步骤。用在多个线程时,只需要把这个CountDownLatch的引用传递到线程里面即可。
是通过一个计数器来实现的,计数器的初始值是线程的数量。每当一个线程执行完毕后,计数器的值就-1,当计数器的值为0时,表示所有线程都执行完毕,然后在闭锁上等待的线程就可以恢复工作了。
注意: 计数器必须大于等于0,只是等于0的时候,计数器就是0,调用await方法时不会阻塞当前线程。CountDownLatch不可能重新初始化或者修改CountDownLatch对象的内部计数器。一个线程调用的countDown()方法happen-before,另外一个线程调用await方法。
源码
该类只提供了一个构造器:
/**
* Constructs a {@code CountDownLatch} initialized with the given count.
*
* @param count the number of times {@link #countDown} must be invoked
* before threads can pass through {@link #await}
* @throws IllegalArgumentException if {@code count} is negative
*/
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
重要的方法:
/调用await()方法的线程会被挂起,它会等待直到count值为0才继续执行
public void await() throws InterruptedException { };
//和await()类似,只不过等待一定的时间后count值还没变为0的话就会继续执行
public boolean await(long timeout, TimeUnit unit) throws InterruptedException { };
//将count值减1
public void countDown() { };
示例:计算20个线程执行共耗费的时间
package pers.zhang.juc.part1;
import java.util.concurrent.CountDownLatch;
/**
* @author zhang
* @date 2020/1/16 - 19:58
*
* CountDownLatch:闭锁,在完成某些运算时,只有其他所有线程的运算全部完成,当前运算才继续执行。
*/
public class TestCountDownLatch {
public static void main(String[] args) {
final CountDownLatch latch = new CountDownLatch(10);
LatchDemo ld = new LatchDemo(latch);
//开始时间
long startTime = System.currentTimeMillis();
for(int i = 0; i < 10; i++){
new Thread(ld).start();
}
//主线程等待其他10个线程执行完毕
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
System.out.println("10个并发线程共耗费时间为:" + (endTime - startTime));
}
}
class LatchDemo implements Runnable{
private CountDownLatch latch;
public LatchDemo(CountDownLatch latch){
this.latch = latch;
}
@Override
public void run() {
synchronized (this){
try {
for(int i = 0; i < 50000; i++){
if(i % 2 == 0){
System.out.println(i);
}
}
}finally {
latch.countDown();//计数器减一,必须执行
}
}
}
}