Java高并发编程基础三大利器之CountDownLatch
引言
上一篇文章我们介绍了AQS
的信号量Semaphore
《Java高并发编程基础三大利器之Semaphore》,接下来应该轮到CountDownLatch
了。
什么是CountDownLatch
CountDownLatch
是通过一个计数器来实现的,计数器的初始值是线程的数量。每当一个线程执行完毕后,计数器的值就减1,当计数器的值为0
时,表示所有线程都执行完毕,然后在闭锁上(调用await方法的线程)等待的线程就可以恢复工作了。
应用场景
CountDownLatch
可以用来干什么呢?有什么应用场景?实际项目中有应用的场景吗?这应该才是大家比较关心的。我们先来看看官网提供的例子是如何进行应用的https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CountDownLatch.html
官方提供了两个demo
我直接把它转成了图片顺带推荐下这个代码转图片的网址https://www.dute.org/code-snapshot 还挺好用的。
官网demo1
The first is a start signal that prevents any worker from proceeding until the driver is ready for them to proceed;
The second is a completion signal that allows the driver to wait until all workers have completed.
- 第一个开始信号(
startSignal
)会阻止任何工人(worker
)开始工作,在司机到来之前。说白了就是司机没来工人就不能干活。 - 第二个是完成信号 (
doneSignal
),允许司机Driver
等待,直到所有的工人完成.说白了就是司机要等到所有工人完工为止。
官网demo2
Another typical usage would be to divide a problem into N parts, describe each part with a Runnable that executes that portion and counts down on the latch, and queue all the Runnables to an Executor. When all sub-parts are complete, the coordinating thread will be able to pass through await.
另一种典型的用法就是把一个大任务拆分N个部分,让多个线程(Worker)执行,每个线程(Worker)执行完自己的部分计数器就减1,当所有子部分都完成后,Driver 才继续向下执行才继续执行。
就好比富士康手机加工的流水线一样,组装一步手机需要一条条的流水线来相互配合完成。一条条流水线(Worker),每条线都干自己的活。有的流水线是贴膜的,有的流水线是打螺丝的,有的流水线是质检的、有的流水线充电的、有的流水线贴膜的。等这些流水线都干完了就把一部手机组装完成了。
上面两个就是官方提供的demo,下面我再来两个我们平时开发中可以用到的栗子:
多个线程等待:模拟并发,让并发线程一起执行。
有时候我们写了接口想去压测下它,看看它的最大并发数大概是多少。当然我们可以使用Jmeter
来进行压测,但是有时候我们不想去下载工具,其实就可以借助CountDownLatch
来实现。
/**
* @author: 公众号:java金融
*/
public class TestCountDownLatch1 {
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(1);
for (int i = 0; i < 5; i++) {
new Thread(() -> {
try {
//所有请求都阻塞在这,等待
countDownLatch.await();
// 调用测试接口
System.out.println(Thread.currentThread().getName() + "开始执行……");
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
// 让请求都准备好
Thread.sleep(2000);
// 让所有请求统一请求
countDownLatch.countDown();
}
}
我们通过CountDownLatch.await()
,让多个参与者线程启动后阻塞等待,然后在主线程 调用CountDownLatch.countdown()
将计数减为0
,让所有线程一起往下执行;以此实现了多个线程在同一时刻并发执行,来模拟并发请求的目的。
单个线程等待:多个线程(任务)完成后,进行汇总合并
/**
* @author: 公众号:java金融
*/
public class TestCountDownLatch1 {
public static void main(String[] args) throws InterruptedException {
int count = 3;
CountDownLatch countDownLatch = new CountDownLatch(count);
for (int i = 0; i < count; i++) {
final int index = i;
new Thread(() -> {
try {
Thread.sleep(1000 + ThreadLocalRandom.current().nextInt(1000));
System.out.println("finish" + index + Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
countDownLatch.countDown();
}
}).start();
}
countDownLatch.await();// 主线程在阻塞,当计数器==0,就唤醒主线程往下执行。
System.out.println("主线程:在所有任务运行完成后,进行结果汇总");
}
}
这种场景应该是用的最多了,比如我们打开一个电商的个人中心页面,我们需要调用,用户信息接口、用户订单接口、用户会员信息等接口,然后合并后一起给到前端,假设每个接口最长耗时为1s
,如果我们同步调用的话最大耗时时间是3s,如果我们采用异步调用然后合并结果,所以最大的耗时时间是3s
。每个接口调用返回数据后调用countDown
方法,让计数器进行减1,当把计数器减为0时的这个线程会去唤醒主线程,让它继续往下走。
CountDownLatch 实现原理
CountDownLatch
是通过AQS
的state
字段来实现的一个计数器,计数器的初始值(state
的值)为new CountDownLatch
设置的数量,每次调用countDown
的时候,state的值会进行减1,最后某个线程将state值减为0时,会把调用了await()
进行阻塞等待的线程进行唤醒。CountDownLatch
重写了tryReleaseShared
这个方法,只有当state
这个字段被设置为0时,也就是tryReleaseShared
返回true
的情况就会执行doReleaseShared
方法,把调用了await的线程进行唤醒。
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
protected boolean tryReleaseShared(int releases) {
// Decrement count; signal when transition to zero
for (;;) {
int c = getState();
if (c == 0)
return false;
int nextc = c-1;
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}
CountDownLatch
的其他源码就不进行分析了,
相信看了这两篇文章《Java高并发编程基础之AQS》、《Java高并发编程基础三大利器之Semaphore》再来看这个还是比较轻松的。
总结
CountDownLatch
不能重新初始化或者修改CountDownLatch
内部计数器的值。CountDownLatch
和Semaphore
在使用AQS
的方式上很相似,在同步状态中都是保存的是当前的计数值。CountDownLatch
的作用就是允许一个或多个线程等待其他线程完成操作,看起来有点类似join()
方法,但其提供了比join
() 更加灵活的API。CountDownLatch
可以手动控制在n个线程里调用n
次countDown
()方法使计数器进行减一操作,也可以在一个线程里调用n次执行减一操作。join
() 的实现原理是不停检查join线程是否存活,如果join
线程存活则让当前线程永远等待。所以两者之间相对来说还是CountDownLatch使用起来较为灵活。
结束
- 由于自己才疏学浅,难免会有纰漏,假如你发现了错误的地方,还望留言给我指出来,我会对其加以修正。
- 如果你觉得文章还不错,你的转发、分享、赞赏、点赞、留言就是对我最大的鼓励。
- 感谢您的阅读,十分欢迎并感谢您的关注。
站在巨人的肩膀上摘苹果:
https://javajr.cn/
https://zhuanlan.zhihu.com/p/148231820
Java高并发编程基础三大利器之CountDownLatch的更多相关文章
- java高并发编程基础之AQS
引言 曾经有一道比较比较经典的面试题"你能够说说java的并发包下面有哪些常见的类?"大多数人应该都可以说出 CountDownLatch.CyclicBarrier.Sempah ...
- [ 高并发]Java高并发编程系列第二篇--线程同步
高并发,听起来高大上的一个词汇,在身处于互联网潮的社会大趋势下,高并发赋予了更多的传奇色彩.首先,我们可以看到很多招聘中,会提到有高并发项目者优先.高并发,意味着,你的前雇主,有很大的业务层面的需求, ...
- 关于Java高并发编程你需要知道的“升段攻略”
关于Java高并发编程你需要知道的"升段攻略" 基础 Thread对象调用start()方法包含的步骤 通过jvm告诉操作系统创建Thread 操作系统开辟内存并使用Windows ...
- java高并发编程(一)
读马士兵java高并发编程,引用他的代码,做个记录. 一.分析下面程序输出: /** * 分析一下这个程序的输出 * @author mashibing */ package yxxy.c_005; ...
- java高并发编程(三)
java高并发主要有三块知识点: synchronizer:同步器,在多个线程之间互相之间怎么进行通讯,同步等: 同步容器:jdk提供了同步性的容器,比如concurrentMap,concurren ...
- 高并发编程基础(java.util.concurrent包常见类基础)
JDK5中添加了新的java.util.concurrent包,相对同步容器而言,并发容器通过一些机制改进了并发性能.因为同步容器将所有对容器状态的访问都串行化了,这样保证了线程的安全性,所以这种方法 ...
- java高并发编程(五)线程池
摘自马士兵java并发编程 一.认识Executor.ExecutorService.Callable.Executors /** * 认识Executor */ package yxxy.c_026 ...
- java高并发编程(四)高并发的一些容器
摘抄自马士兵java并发视频课程: 一.需求背景: 有N张火车票,每张票都有一个编号,同时有10个窗口对外售票, 请写一个模拟程序. 分析下面的程序可能会产生哪些问题?重复销售?超量销售? /** * ...
- java高并发编程(二)
马士兵java并发编程的代码,照抄过来,做个记录. 一.分析下面面试题 /** * 曾经的面试题:(淘宝?) * 实现一个容器,提供两个方法,add,size * 写两个线程,线程1添加10个元素到容 ...
随机推荐
- Nestjs入门学习教程
初次接触Nest,有问题欢迎指出: 简介 NestJS是一个用于构建高效.可扩展的Node.js服务器端应用程序的开发框架.简单来说是一款Node.js的后端框架. 它利用JavaScript的渐进增 ...
- pycharm 与 anaconda 关联
anaconda Anaconda指的是一个开源的Python发行版本,集成了许多数据分析的库. 使用tersorflow进行机器学习时常用Anaconda pycharm PyCharm是一种Pyt ...
- SPOJ - LCS2 Longest Common Substring II(后缀自动机)题解
题意: 求\(n\)个串的最大\(LCS\). 思路: 把第一个串建后缀自动机,然后枚举所有串.对于每个串,求出这个串在\(i\)节点的最大匹配为\(temp[i]\)(当前串在这个节点最多取多少), ...
- exgcd&&中国剩余定理专题练习
hdu1573求中国剩余定理解的个数 #include <iostream> #include <cstdio> using namespace std; int a[100] ...
- SSL 数据加密原理简述
最近调试mqtt协议,为了保证数据安全性和将来客户端的对云的兼容性选择了openssl作为安全加密中间层,而没有使用私有的加密方式.所以花了点时间学习了一下ssl 加密流程整理如下: 因为正常正式使用 ...
- Fullscreen API All In One
Fullscreen API All In One 全屏显示 https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API https ...
- holy shit StackOverflow
holy shit StackOverflow refs https://stackoverflow.com/users/5934465/xgqfrms?tab=questions xgqfrms 2 ...
- css & background-image & full page width & background-size
css & background-image & full page width & background-size https://css-tricks.com/perfec ...
- HANNAH WHITE:不拖延的人生是什么样子的?
不拖延的人生,究竟是什么样子呢?近日,星盟投资总经理HANNAH在一档人物采访栏目中表示,不拖延的人生,真的是太爽了! HANNAH在栏目中讲了一个曾经公司同事的故事.她说,那位同事总是喜欢拖延.每次 ...
- Mila Fletcher :其实高度自律的人生并没有那么难养成
在日常生活中,我们经常会发现,不论是学习,考证,工作,都需要坚持付出.但是很多人都没有办法在枯燥的学习过程中持续下去,这通常是因为不够自律导致的.但是尽管大家都知道自律是多么重要,却没有几个人可以真正 ...