一. 什么是CountDownLatch
CountDownLatch: 又称闭锁,CountDownLatch 这个类能够使一个线程等待其他线程完成各自的工作后再执行。例如,应用程序的主线程希望在负责启动框架服务的线程已经启动所有的框架服务之后再执行。
CountDownLatch 是通过一个计数器来实现的,计数器的初始值为初始任务的数量。每当完成了一个任务后,计数器的值就会减 1 (CountDownLatch.countDown()方法)。当计数器值减到0 时,表示所有的任务已经完成,然后在闭锁上等待 CountDownLatch.await()方法的线程就可以恢复执行任务。
二. CountDownLatch执行流程
开始执行前等待 n 个线程完成各自任务:例如处理 excel 中多个表单。
这张图描述的是TW1与TW2两个线程执行时,需要等待另外五个任务(CNT)执行结束后,才能继续执行。然后启动4个线程Ta、Tb、Tc、Td。首先Td执行完一个任务调用countDown(),计数器减一;然后是Tb执行完任务调用countDown(),计数器减一;然后依次Td,Ta,Tc执行结束,CountDownLatch减到0,唤醒TW1和TW2,然后TW1,TW2,Ta,Td继续执行自己的业务。
从这个流程中我们可以得到:
1. 待执行任务不用与线程数相等;
2. 待执行任务执行结束仍可以继续执行;
三. CountDownLatch方法解释
1. await()方法
调用方法的线程会等待,也可以设置等待时间。直到 latch减到0,(除非线程被中断)
/*
*Causes the current thread to wait until the latch has counted down to zero,
*unless the thread is {@linkplain Thread#interrupt interrupted}.
*/
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
/*
*Causes the current thread to wait until the latch has counted down to
* zero, unless the thread is {@linkplain Thread#interrupt interrupted},
* or the specified waiting time elapses.
*/
public boolean await(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}
2. countDown()方法
使得 latch 计数器减一
/**
* Decrements the count of the latch, releasing all waiting threads if
* the count reaches zero.
*
* <p>If the current count is greater than zero then it is decremented.
* If the new count is zero then all waiting threads are re-enabled for
* thread scheduling purposes.
*
* <p>If the current count equals zero then nothing happens.
*/
public void countDown() {
sync.releaseShared(1);
}
3. getCount()方法
获取当前 latch 的当前数字
/**
* Returns the current count.
*
* <p>This method is typically used for debugging and testing purposes.
*
* @return the current count
*/
public long getCount() {
return sync.getCount();
}
四. CountDownLatch测试案例
// 需要同时进行的执行的线程数
static CountDownLatch latch = new CountDownLatch(5);
// 执行线程
static class ThreadOne implements Runnable{
@Override
public void run() {
int random = new Random().nextInt(1000);
SleepUtil.sleep(random);
latch.countDown();
System.out.println("one thread execute over ......");
}
}
//调度
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < latch.getCount(); i++) {
new Thread(new ThreadOne()).start();
}
latch.await();
System.out.println("main thread execute over ......");
}
执行结果: