CountDownLatch:别浪,等人齐再团!

一入王者深似海,从此对象是路人。

哈喽观众老爷们大家好,我是战神吕布字奉先,今天给大家来一部吕布的教学视频!

咳咳,不对。大家好,我是磊哥,今天给大家来一篇 CountDownLatch 的文章。

在开始之前,先问大家一个非常专业的技术性问题:打团战最怕_____?

一道非常简单的送分题,如果答不对,那磊哥就要批评你了,哈哈。

可能有人会说:打团战最怕猪队友,但比猪队友更可怕的是打团战人不齐啊兄弟,想想在打团时如果是 5V2 是怎么一幅画面,心痛到不敢想????????‍♀️。

等人齐再团

磊哥在儿子没有出生之前,也是资深的农药玩家,至于段位吗?别问!问就是青铜。虽然磊哥的段位不是很高,但基本的大局观还是有的,毕竟也是打过几年 Dota 和 LOL 的青铜玩家是吧?哈哈。

农药和其他 Moba 类游戏是一样的,想要取胜,必须要把握好每次团战,而每次团战的关键在于等人齐了再开团,是吧?而这个思想正好和咱们要讲得 CountDownLatch 的思想是一致的,咱们来看看是怎么回事吧。

吾有上将“CountDownLatch”

想象一下这样一个场景,当我们需要等待某些线程执行完之后,再执行主线程的代码,要怎么实现?

可能有人会说,简单,用 join() 方法等待线程执行完成之后再执行主线程就行了,实现代码是这样的:

// 创建线程1
Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {// do something}
});
t1.start();// 创建线程2
Thread t2 = new Thread(new Runnable() {@Overridepublic void run() {// do something}
});
t2.start();// 等待线程 1和线程 2 执行完
t1.join();
t2.join();

当然,如果使用的是 Thread 来执行任务,那这种写法也是可行的。然而真实的(编码)环境中我们是不会使用 Thread 来执行多任务的,而是会使用线程池来执行多任务,这样可以避免线程重复启动和销毁所带来的性能开销,实现代码如下:

// 创建固定线程数的线程池
ExecutorService executorService = Executors.newFixedThreadPool(2);
// 任务一
executorService.submit(new Runnable() {@Overridepublic void run() {// do something}
});
// 任务二
executorService.submit(new Runnable() {@Overridepublic void run() {// do something}
});

那么这时候问题来了,线程池是没有 join() 方法的,那要怎么实现等待呢?

这个时候就要派出我方大将“CountDownLatch”啦。

吾有上将潘凤,可斩华雄... 出场数秒,潘凤...“卒”。

等等导演,我觉得剧情应该是这样的...

CountDownLatch使用

为了实现等待所有线程池执行完之后再执行主线程的逻辑,我决定使用 AQS(AbstractQueuedSynchronizer,抽象同步框架)下的著名类 CountDownLatch 来实现此功能,具体的实现代码如下:

public static void main(String[] args) throws InterruptedException {// 创建 CountDownLatchCountDownLatch countDownLatch = new CountDownLatch(2);// 创建固定线程数的线程池ExecutorService executorService = Executors.newFixedThreadPool(2);// 任务一executorService.submit(new Runnable() {@Overridepublic void run() {// do somethingtry {// 让此任务执行 1.2sThread.sleep(1200);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("我是任务一");countDownLatch.countDown();}});// 任务二executorService.submit(new Runnable() {@Overridepublic void run() {// do somethingtry {// 让此任务执行 1.2sThread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("我是任务二");countDownLatch.countDown();}});// 等待任务执行完成countDownLatch.await();System.out.println("程序执行完成~");
}

以上程序执行结果如下:

从上述结果可以看出,主线程的执行是等待任务一和任务二都执行完成之后才执行的。

CountDownLatch实现原理

CountDownLatch 中 count down 是倒数的意思,latch 则是门闩的含义。整体含义可以理解为倒数的门栓,似乎有点“321,芝麻开门”的感觉,CountDownLatch 的作用也正是如此。

CountDownLatch 在创建的时候需要传入一个整数,在这个整数“倒数”到 0 之前,主线程需要一直挂起等待,直到其他的线程都执行之后,主线才能继续执行。

CountDownLatch执行流程

CountDownLatch 的实现是在其内部创建并维护了一个 volatile 类型的整数计数器,当调用 countDown() 方法时,会尝试将整数计数器 -1,当调用 wait() 方法时,当前线程就会判断整数计数器是否为 0,如果为 0,则继续往下执行,如果不为 0,则使当前线程进入等待状态,直到某个线程将计数器设置为 0,才会唤醒在 await() 方法中等待的线程继续执行。

CountDownLatch常用方法

// 线程被挂起直到 count 值为 0 才继续执行
public void await() throws InterruptedException { };   // 和 await() 类似,只不过等待一定的时间后 count 值还没变为 0 的话就会继续执行
public boolean await(long timeout, TimeUnit unit) throws InterruptedException { };  // 将 count 值减 1
public void countDown() { };

总结

使用 CountDownLatch 可以实现等待所有任务执行完成之后再执行主任务的功能,它就好像比赛中要等待所有运动员都完成比赛之后再公布排名一样,当然我们在玩农药的时候也是一样,要等所有人集合完毕之后再开团,这是制胜的关键。而 CountDownLatch 是通过计数器来实现等待功能的,当创建 CountDownLatch 时会设置一个大于 0 的计数器,每次调用 countDown() 方法时计数器的值会 -1,直到计数器值变为 0 时,等待的任务就可以继续执行了。

参考 & 鸣谢

www.jianshu.com/p/128476015902

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/544887.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ASP在 Web.config 中创建数据库连接字符串

在 Web.config 中创建数据库连接串我们需要在网站的配置文件中增加一些行&#xff0c;以便 Entity Framework 知道如何连接到我们的数据库&#xff0c;双击Web.config 文件。 卷到文件的最后&#xff0c;然后增加一个 <connectionStrings> 的配置节&#xff0c;如何所示&…

easyUI layout 中使用tabs+iframe解决请求两次方法

demo中的事例在加载tab页面时是 1 function createFrame(url) {2 var s <iframe name"iframepanel" scrolling"no" frameborder"0" src" url " style"width:100%;height:100%;"></iframe>;3 …

jQuery 的选择器 元素选择器

>> 转&#xff1a;http://www.cnblogs.com/onlys/articles/jQuery.htmljQuery 的选择器可谓之强大无比&#xff0c;这里简单地总结一下常用的元素查找方法 $("#myELement") 选择id值等于myElement的元素&#xff0c;id值不能重复在文档中只能有一个id值是my…

Java FilterInputStream skip()方法与示例

FilterInputStream类skip()方法 (FilterInputStream Class skip() method) skip() method is available in java.io package. skip()方法在java.io包中可用。 skip() method is used to skip the given number of bytes of data from this FilterInputStream. skip()方法用于从…

附彩蛋|Spring Security 竟然故意延长登录时间?知道真相的我惊呆了!

2011年12月21日&#xff0c;有人在网络上公开了一个包含600万个CSDN用户资料的数据库&#xff0c;数据全部为明文储存&#xff0c;包含用户名、密码以及注册邮箱。事件发生后CSDN在微博、官方网站等渠道发出了声明&#xff0c;解释说此数据库系2009年备份所用&#xff0c;因不明…

DirectX 矩阵

基础&#xff1a; 下标&#xff1a;第一个下标为该元素所在行的索引&#xff0c;第二个下标为该元素所在列的索引。如下图所示 行向量和列向量&#xff1a;只有单行的向量称为行向量&#xff0c;只有单列的称之为列向量。 相等 维数和元素都相等 数乘(与标量相乘) 每一个元素与…

div 图片滚动 / 文字滚动

今天研究了一下图片滚动&#xff0c;网上有很多可以使用的例子&#xff0c;所以先是找了一个用的是表格布局的&#xff0c;如下&#xff1a;<!DOCTYPE html> <html xmlns"http://www.w3.org/1999/xhtml"> <head><meta http-equiv"Content-…

为什么阿里内部不允许用Executors创建线程池?

来源&#xff1a;cnblogs.com/zjfjava/p/11227456.html1. 通过Executors创建线程池的弊端在创建线程池的时候&#xff0c;大部分人还是会选择使用Executors去创建。下面是创建定长线程池&#xff08;FixedThreadPool&#xff09;的一个例子&#xff0c;严格来说&#xff0c;当使…

Java FilePermission暗含()方法与示例

FilePermission类implies()方法 (FilePermission Class implies() method) implies() method is available in java.io package. implies()方法在java.io包中可用。 implies() method is used to check whether this FilePermission implies the given permission (perm) or no…

填充

1. $number 68 {0:d7} -f $number2. $number1 68$number1.PadLeft(7,0)转载于:https://www.cnblogs.com/IvanChen/p/4492976.html

RabbitMQ中7种消息队列和保姆级代码演示!

blog.csdn.net/qq_32828253/article/details/110450249七种模式介绍与应用场景简单模式&#xff08;Hello World&#xff09;做最简单的事情&#xff0c;一个生产者对应一个消费者&#xff0c;RabbitMQ相当于一个消息代理&#xff0c;负责将A的消息转发给B应用场景&#xff1a;…

如何在使用ASPMVC4的分部视图中获取数据展示

如何在使用ASPMVC4的分部视图中获取数据展示在ASPMVC4中&#xff0c;创建的网站项目会用到分部视图&#xff0c;通过Html.Partial("视图名")来加载到页面上&#xff1b;但是如何把数据附加到分部视图中在加载到主页上&#xff0c;是个新的问题。暂时发现这个问题有两…

Java枚举getDeclaringClass()方法与示例

枚举类getDeclaringClass()方法 (Enum Class getDeclaringClass() method) getDeclaringClass() method is available in java.lang package. getDeclaringClass()方法在java.lang包中可用。 getDeclaringClass() method is used to return the Class object denoting the enum…

项目已被os x使用 不能打开-黑苹果之路

之前复制了几个视频文件到NTFS的盘上&#xff0c;在mac中始终无法使用&#xff08;甚至是chmod&#xff09;&#xff0c;无论是哪种播放软件&#xff0c;甚至改成dmg类型都无法打开&#xff0c;报“项目已被os x使用 不能打开”&#xff0c;用ls命令发现文件属性中多了个标志&a…

CyclicBarrier:人齐了,老司机就发车了!

作者 | 王磊来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;上一篇咱讲了 CountDownLatch 可以解决多个线程同步的问题&#xff0c;相比于 join 来说它的应用范围更广&#xff0c;不仅可…

Leetcode 2975. Maximum Square Area by Removing Fences From a Field

Leetcode 2975. Maximum Square Area by Removing Fences From a Field 1. 解题思路2. 代码实现 题目链接&#xff1a;2975. Maximum Square Area by Removing Fences From a Field 1. 解题思路 这一题思路上是比较直接的&#xff0c;就是直接求出横向和纵向上可能的interva…

判断ip是否合法

//用来判断ip是否合法public boolean checkIp(String tempIp) {String regex "(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)){3}";Pattern p Pattern.compile(regex);Matcher m p.matcher(tempIp);return m.matches();}

Java类类getPackage()方法及示例

类的类getPackage()方法 (Class class getPackage() method) getPackage() method is available in java.lang package. getPackage()方法在java.lang包中可用。 getPackage() method is used to return the package of this class, we find the package of the class by using…

iOS平台快速发布HT for Web拓扑图应用

iOS平台一直是封闭的生态圈&#xff0c;iOS开发者要缴纳年费加入开发者计划才可进行iOS平台的APP开发测试&#xff0c;所开发的APP需要上传到App Store经过苹果审核以后才可对外发布。如果要开发企业内部应用&#xff0c;则要缴纳更高的费用购买企业账户才可以。 对于现在火如荼…

事务注解 @Transactional 失效的3种场景及解决办法

Transactional失效场景第一种 Transactional注解标注方法修饰符为非public时&#xff0c;Transactional注解将会不起作用。例如以下代码&#xff0c;定义一个错误的Transactional标注实现&#xff0c;修饰一个默认访问符的方法&#xff1a;/*** author zhoujy**/ Component pub…