最近这边连续下了好几天的雨了啊啊啊,你那边呢?
嗯哼?这开场的感觉不对呀,好尬,哈哈哈哈~
直接进入正题吧。
什么是CountDownLatch
这个是在JDK1.5开始就出现的,并发编程工具类。
这里偷懒下,直接看下源码上的类注释吧,相信你看完就差不多大概知道这个干啥子用的了。
在这里,请允许我用本人的蹩脚英文稍微翻译下:
可以允许一个或者多个线程等待,直到一组在其它线程里的操作都完成,然后再执行。
初始化CountDownLatch时提供一个count数,主方法一直将被阻塞直到多次调用CountDownLatch对象的countDown方法使得count数减至0为止。当所有等待的线程都被释放了,await后的一系列调用都立即返回(执行)。CountDownLatch只能执行一次这样的控制,如果你需要每个版本都重置下count数,可以考虑下CyclicBarrier。
怎么用呢
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(3);//计数器最初:3个任务
MyWork work1 = new MyWork(countDownLatch, "1号");
MyWork work2 = new MyWork(countDownLatch, "2号");
MyWork work3 = new MyWork(countDownLatch, "3号");
//固定大小线程池并行执行(每个任务都在不同的线程池里)
ExecutorService executorService = Executors.newFixedThreadPool(2);
executorService.submit(work1);
executorService.submit(work2);
executorService.submit(work3);
//等待所有的任务完成
countDownLatch.await();
//所有任务完成,可以干其它的事情啦
System.out.println("所有任务都完成啦");
}
static class MyWork implements Runnable {
CountDownLatch countDownLatch;
private String missionFlg;
public MyWork(CountDownLatch countDownLatch, String missionFlg) {
this.countDownLatch = countDownLatch;
this.missionFlg = missionFlg;
}
@Override
public void run() {
try {
//执行业务逻辑
System.out.println(Thread.currentThread().getName() + "====> 执行任务" + missionFlg + "开始");
Random random = new Random();
//线程停留随机停留,表示任务的执行
TimeUnit.SECONDS.sleep(random.nextInt(5));
System.out.println(Thread.currentThread().getName() + "====> 执行任务" + missionFlg + "结束");
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName() + "====> 执行任务" + missionFlg + "出现异常");
} finally {
//异常的状态下,也要记得发出信号,当前任务完成
reduce();
}
}
public void reduce() {
//计数器减一
countDownLatch.countDown();
}
}
执行结果:
自己使用过的场景
说一下自己一次的使用场景吧:
需求:产品给我一个表格,里面大概500多条下载链接,需要我临时写一个工具,快速地全部下载 并且要 生成一个下载结果(原链接和下载到磁盘的路径对照关系)。
实现:
- 对任务列表进行拆分多个小的列表 list1,list2,list3 … listn;
- 定义一个CountDownLatch对象,大小和上面的list的个数一致;
- 启动 20 个线程池,把拆分后的列表依次丢到线程池;
- 每个list的任务,都需要记录下每条记录的执行结果,存储到Redis 中;
- 每个线程池每次执行完一个list 都 CountDownLatch里的计数器减一;
- CountDownLatch#await 后写上生成 下载结果的 逻辑,这里就是从Redis 中读取执行结果列表,生成文件 。