当前位置:网站首页>多线程并发之CountDownLatch阻塞等待
多线程并发之CountDownLatch阻塞等待
2022-07-01 16:33:00 【鱼找水需要时间】
1. 简介
CountDownLatch中count down是倒数的意思,latch则是门闩、锁住的含义。整体含义可以理解为倒数的门栓。CountDownLatch的作用也是如此,在构造CountDownLatch的时候需要传入一个整数n(必须>0),在这个整数“倒数”到0之前,主线程需要等待在门口,而这个“倒数”过程则是由各个执行线程驱动的,每个线程执行完一个任务“倒数”一次。总结来说,CountDownLatch的作用就是等待其他的线程都执行完任务,必要时可以对各个任务的执行结果进行汇总,然后主线程才继续往下执行。
CountDownLatch主要有两个方法:countDown()和await()。countDown()方法用于使计数器减一,其一般是执行任务的线程调用,await()方法则使调用该方法的线程处于等待状态,其一般是主线程调用。这里需要注意的是,countDown()方法并没有规定一个线程只能调用一次,当同一个线程调用多次countDown()方法时,每次都会使计数器减一;另外,await()方法也并没有规定只能有一个线程执行该方法,如果多个线程同时执行await()方法,那么这几个线程都将处于等待状态,并且以共享模式享有同一个锁。
2. 方法API
方法:
| 方法 | 说明 |
|---|---|
| await() | 使当前线程进入同步队列进行等待,直到latch的值被减到0或者当前线程被中断,当前线程就会被唤醒。 |
| await(long timeout, TimeUnit unit) | 等待timeout时间后,count的值还不是0,不再等待,那么将继续执行 |
| countDown() | 使latch的值减1,如果减到了0,则会唤醒所有等待在这个latch上的线程。 |
| getCount() | 获得latch的数值。 |
3. 使用
3.1 await()
示例:
CountDownLatch count = new CountDownLatch(3);
new Thread(()->{
//处理业务1
try {
TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) {
e.printStackTrace(); } finally {
count.countDown();//确保每个任务执行完递减
}
}, "t1").start();
new Thread(()->{
//处理业务2
try {
TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) {
e.printStackTrace(); } finally {
count.countDown();//确保每个任务执行完递减
}
}, "t2").start();
new Thread(()->{
//处理业务3
try {
TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) {
e.printStackTrace(); } finally {
count.countDown(); //确保每个任务执行完递减
}
}, "t3").start();
long startTime = System.currentTimeMillis();
count.await(); // 等待任务执行
long endTime = System.currentTimeMillis();
System.out.println("任务执行完成,耗时:" + (endTime - startTime) + "毫秒");
结果:

3.2 boolean await(long timeout, TimeUnit unit)
boolean await(long timeout, TimeUnit unit)示例:
CountDownLatch count = new CountDownLatch(3);
new Thread(()->{
//处理业务1
try {
TimeUnit.SECONDS.sleep(1);
System.out.println("task1 over");} catch (InterruptedException e) {
e.printStackTrace(); } finally {
count.countDown();//确保每个任务执行完递减
}
}, "t1").start();
new Thread(()->{
//处理业务2
try {
TimeUnit.SECONDS.sleep(2);
System.out.println("task2 over");} catch (InterruptedException e) {
e.printStackTrace(); } finally {
count.countDown();//确保每个任务执行完递减
}
}, "t2").start();
new Thread(()->{
//处理业务3
try {
TimeUnit.SECONDS.sleep(3);
System.out.println("task3 over");} catch (InterruptedException e) {
e.printStackTrace(); } finally {
count.countDown(); //确保每个任务执行完递减
}
}, "t3").start();
long startTime = System.currentTimeMillis();
boolean await = count.await(2, TimeUnit.SECONDS);// 指定等待时间,如果当前有任务未执行完成则返回false
System.out.println("所有任务是否执行完成:" + (await ? "是" : "否"));
System.out.println("计数器值为:" + count.getCount());
long endTime = System.currentTimeMillis();
System.out.println("任务执行完成,耗时:" + (endTime - startTime) + "毫秒");
分析:
开启三个线程去执行任务,任务1、任务2、任务3耗时依次为1s、2s、3s
计数器await等待2s,如果2s后计数器值不为0(即三个任务中有任务未执行完成),那么就返回false。可以用在一些比较耗时长的任务上,例如调用第三方接口、业务线比较长,当超过指定时间后就当作失败处理,避免服务一直处于等待阻塞状态。
结果:

4. CountDownLatch和Thread.join()方法的区别
1、
CountDownLatch的作用就是允许一个或多个线程等待其他线程完成操作,看起来有点类似join()方法,但其提供了比join()更加灵活的API。2、
CountDownLatch可以手动控制在n个线程里调用n次countDown()方法使计数器进行减一操作,也可以在一个线程里调用n次执行减一操作。 而join()的实现原理是不停检查join线程是否存活,如果join线程存活则让当前线程永远等待。所以两者之间相对来说还是CountDownLatch使用起来较为灵活。
5. CountDownLatch的不足
CountDownLatch是一次性的,计算器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当CountDownLatch使用完毕后,它不能再次被使用。
6. 扩展
如果采用多线程异步任务Future,通过CompletableFuture.allOf也可以实现同样的效果,阻塞等待任务执行结果,参考文章多线程Future,CompletableFuture
边栏推荐
- Flux d'entrées / sorties et opérations de fichiers en langage C
- 剑指 Offer II 105. 岛屿的最大面积
- Red team Chapter 8: blind guess the difficult utilization process of the package to upload vulnerabilities
- Activity的生命周期和启动模式详解
- Redis6.0 new features
- P2893 [usaco08feb] making the grade g (DP & priority queue)
- SystemVerilog structure (II)
- Rhcsa Road
- FRP intranet penetration, reverse proxy
- [JetsonNano] [教程] [入门系列] [三] 搭建TensorFlow环境
猜你喜欢

机器学习11-聚类,孤立点判别

SQL question brushing 627 Change gender

Bugku's file contains

毕业季 | 华为专家亲授面试秘诀:如何拿到大厂高薪offer?

模板引擎Velocity 基础

博睿数据一体化智能可观测平台入选中国信通院2022年“云原生产品名录”

C語言輸入/輸出流和文件操作

Template Engine Velocity Foundation

sql刷题586. 订单最多的客户

Tutorial on the principle and application of database system (003) -- MySQL installation and configuration: manually configure MySQL (Windows Environment)
随机推荐
P2893 [USACO08FEB] Making the Grade G(dp&优先队列)
数据库系统原理与应用教程(004)—— MySQL 安装与配置:重置 MySQL 登录密码(windows 环境)
sql刷题584. 寻找用户推荐人
Redis6.0 new features
阿里云、追一科技抢滩对话式AI
Advantages, values and risks of chain games compared with traditional games
Redis 分布式鎖
AI高考志愿填报:大厂神仙打架,考生付费围观
VMware 虛擬機啟動時出現故障:VMware Workstation 與 Hyper-v 不兼容...
SQL question brushing 586 Customers with the most orders
Redis 分布式锁
VMware 虚拟机启动时出现故障:VMware Workstation 与 Hyper-v 不兼容...
What is the effect of choosing game shield safely in the game industry?
Research and investment strategy report of hydroxypropyl beta cyclodextrin industry in China (2022 Edition)
剑指 Offer II 105. 岛屿的最大面积
Girls who want to do software testing look here
P2592 [zjoi2008] birthday party (DP)
挖财学堂班主任给的证券账户安全吗?能开户吗?
模板引擎Velocity 基础
Preliminary study on golang crawler framework