Java—CountDownLatch使用详解
CountDownLatch介绍
CountDownLatch概述
CountDownLatch一般用作多线程倒计时计数器,强制它们等待其他一组(CountDownLatch的初始化决定)任务执行完成。- 有一点要说明的是
CountDownLatch初始化后计数器值递减到0的时候,不能再复原的,这一点区别于Semaphore,Semaphore是可以通过release操作恢复信号量的。
CountDownLatch使用原理
使用原理
- 创建CountDownLatch并设置计数器值。
- 启动多线程并且调用CountDownLatch实例的countDown()方法。
- 主线程调用
await()方法,这样主线程的操作就会在这个方法上阻塞,直到其他线程完成各自的任务,count值为0,停止阻塞,主线程继续执行。
使用模板
public class CountDownLatchModule {
//线程数
private static int N = 10;
// 单位:min
private static int countDownLatchTimeout = 5;
public static void main(String[] args) {
//创建CountDownLatch并设置计数值,该count值可以根据线程数的需要设置
CountDownLatch countDownLatch = new CountDownLatch(N);
//创建线程池
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
for (int i = 0; i < N; i++) {
cachedThreadPool.execute(() ->{
try {
System.out.println(Thread.currentThread().getName() + " do something!");
} catch (Exception e) {
System.out.println("Exception: do something exception");
} finally {
//该线程执行完毕-1
countDownLatch.countDown();
}
});
}
System.out.println("main thread do something-1");
try {
countDownLatch.await(countDownLatchTimeout, TimeUnit.MINUTES);
} catch (InterruptedException e) {
System.out.println("Exception: await interrupted exception");
} finally {
System.out.println("countDownLatch: " + countDownLatch.toString());
}
System.out.println("main thread do something-2");
//若需要停止线程池可关闭;
// cachedThreadPool.shutdown();
}
运行结果:
main thread do something-1
pool-1-thread-1 do something!
pool-1-thread-2 do something!
pool-1-thread-3 do something!
pool-1-thread-5 do something!
pool-1-thread-6 do something!
pool-1-thread-7 do something!
pool-1-thread-8 do something!
pool-1-thread-4 do something!
pool-1-thread-9 do something!
pool-1-thread-10 do something!
countDownLatch: java.util.concurrent.CountDownLatch@76fb509a[Count = 0]
main thread do something-2
CountDownLatch常用方法

public void await() throws InterruptedException:调用await()方法的线程会被挂起,等待直到count值为0再继续执行。public boolean await(long timeout, TimeUnit unit) throws InterruptedException:同await(),若等待timeout时长后,count值还是没有变为0,不再等待,继续执行。时间单位如下常用的毫秒、天、小时、微秒、分钟、纳秒、秒。

public void countDown(): count值递减1.public long getCount():获取当前count值。public String toString():重写了toString()方法,多打印了count值,具体参考源码。
CountDownLatch使用场景
一个程序中有N个任务在执行,我们可以创建值为N的CountDownLatch,当每个任务完成后,调用一下countDown()方法进行递减count值,再在主线程中使用await()方法等待任务执行完成,主线程继续执行。
CountDownLatch源码
构造方法源码
/**
* Constructs a {@code CountDownLatch} initialized with the given count.
*
* @param count the number of times {@link #countDown} must be invoked
* before threads can pass through {@link #await}
* @throws IllegalArgumentException if {@code count} is negative
*/
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
toString()方法源码
/**
* Returns a string identifying this latch, as well as its state.
* The state, in brackets, includes the String {@code "Count ="}
* followed by the current count.
*
* @return a string identifying this latch, as well as its state
*/
public String toString() {
return super.toString() + "[Count = " + sync.getCount() + "]";
}
CountDownLatch示例
作为线程启动信号
代码
public class CountDownLatchTest {
/**
* a start signal that prevents any worker from proceeding
* until the driver is ready for them to proceed;
* @param args
* @throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
CountDownLatch startSignal = new CountDownLatch(1);
CountDownLatch doneSignal = new CountDownLatch(10);
for (int i = 0; i < 10; i++) {
// create and start threads
new Thread(new Worker(startSignal, doneSignal)).start();
}
// don't let run yet
System.out.println("do something else 1");
// let all threads proceed
startSignal.countDown();
System.out.println("do something else 2");
// wait for all to finish
doneSignal.await();
System.out.println("wait for all to finsh");
}
static class Worker implements Runnable{
private final CountDownLatch startSignal;
private final CountDownLatch doneSignal;
Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {
this.startSignal = startSignal;
this.doneSignal = doneSignal;
}
@Override
public void run() {
try {
startSignal.await();
doWork();
doneSignal.countDown();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
void doWork() {
System.out.println("do work!");
}
}
}
运行结果
do something else 1
do something else 2
do work!
do work!
do work!
do work!
do work!
do work!
do work!
do work!
do work!
do work!
wait for all to finsh
从运行结果可以看出:
- 主线程先打印
do something else 1和do something else 2。因为startSignal.countDown();完后,count才为0,子线程才能打印。 - 因为
startSignal.await();是在子线程内,所有子线程都等待startSignal.countDown()执行后才能打印do work!。 doneSignal.await();等待所有子线程执行后,每次都doneSignal.countDown(),最后count为0,主线程才执行打印wait for all to finsh。
作为线程等待完成信号
代码
public class CountDownLatchTest2 {
/**
* a completion signal that allows the driver to wait
* until all workers have completed.
* @param args
* @throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
CountDownLatch doneSignal = new CountDownLatch(5);
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
// create and start threads
cachedThreadPool.execute(new Worker(doneSignal, i));
}
// don't let run yet
System.out.println("do something else 1");
// wait for all to finish
doneSignal.await();
System.out.println("===========================count: " + doneSignal.getCount());
System.out.println("do something else 2");
cachedThreadPool.shutdown();
}
static class Worker implements Runnable{
private final CountDownLatch doneSignal;
private final int i;
Worker(CountDownLatch doneSignal, int i) {
this.doneSignal = doneSignal;
this.i = i;
}
@Override
public void run() {
try {
doWork();
doneSignal.countDown();
System.out.println("i = " + i + ", " + doneSignal.toString());
} catch (Exception ex) {
ex.printStackTrace();
}
}
void doWork() {
System.out.println("do work!");
}
}
}
运行结果
do something else 1
do work!
i = 0, java.util.concurrent.CountDownLatch@128abd43[Count = 4]
do work!
i = 1, java.util.concurrent.CountDownLatch@128abd43[Count = 3]
do work!
i = 2, java.util.concurrent.CountDownLatch@128abd43[Count = 2]
do work!
i = 3, java.util.concurrent.CountDownLatch@128abd43[Count = 1]
do work!
i = 4, java.util.concurrent.CountDownLatch@128abd43[Count = 0]
===========================count: 0
do something else 2
do work!
i = 5, java.util.concurrent.CountDownLatch@128abd43[Count = 0]
do work!
i = 6, java.util.concurrent.CountDownLatch@128abd43[Count = 0]
do work!
i = 7, java.util.concurrent.CountDownLatch@128abd43[Count = 0]
do work!
i = 8, java.util.concurrent.CountDownLatch@128abd43[Count = 0]
do work!
i = 9, java.util.concurrent.CountDownLatch@128abd43[Count = 0]
从运行结果可以看出,主线程是等待其他线程运行了5次结束后就打印了do something else 2信息,因为CountDownLatch数值为5。
Java—CountDownLatch使用详解的更多相关文章
- 最强Java并发编程详解:知识点梳理,BAT面试题等
本文原创更多内容可以参考: Java 全栈知识体系.如需转载请说明原处. 知识体系系统性梳理 Java 并发之基础 A. Java进阶 - Java 并发之基础:首先全局的了解并发的知识体系,同时了解 ...
- Java 字符串格式化详解
Java 字符串格式化详解 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 文中如有纰漏,欢迎大家留言指出. 在 Java 的 String 类中,可以使用 format() 方法 ...
- Java 序列化Serializable详解
Java 序列化Serializable详解(附详细例子) Java 序列化Serializable详解(附详细例子) 1.什么是序列化和反序列化Serialization(序列化)是一种将对象以一连 ...
- Java String类详解
Java String类详解 Java字符串类(java.lang.String)是Java中使用最多的类,也是最为特殊的一个类,很多时候,我们对它既熟悉又陌生. 类结构: public final ...
- 最新java数组的详解
java中HashMap详解 http://alex09.iteye.com/blog/539545 总结: 1.就像引用类型的数组一样,当我们把 Java 对象放入数组之时,并不是真正的把 Java ...
- JAVA IO 类库详解
JAVA IO类库详解 一.InputStream类 1.表示字节输入流的所有类的超类,是一个抽象类. 2.类的方法 方法 参数 功能详述 InputStream 构造方法 available 如果用 ...
- 转:Java HashMap实现详解
Java HashMap实现详解 转:http://beyond99.blog.51cto.com/1469451/429789 1. HashMap概述: HashMap是基于哈希表的M ...
- 淘宝JAVA中间件Diamond详解(2)-原理介绍
淘宝JAVA中间件Diamond详解(二)---原理介绍 大家好,通过第一篇的快速使用,大家已经对diamond有了一个基本的了解.本次为大家带来的是diamond核心原理的介绍,主要包括server ...
- 【转】 java中HashMap详解
原文网址:http://blog.csdn.net/caihaijiang/article/details/6280251 java中HashMap详解 HashMap 和 HashSet 是 Jav ...
随机推荐
- 敏捷与OKR实践(如何让OKR与敏捷计划共存)
僵化的详细长期计划(根据消耗的预算跟踪进度)正在敏捷组织中迅速成为对过去的褪色怀旧记忆,这由预测和非静态路线图代替.定期在这些可视化文件前聚会,您将能够学习.共享并触发重要的对话,解决依赖性并邀请服务 ...
- MySQL系列(二)
查看\创建\使用\删除 数据库 用户管理及授权实战 局域网远程连接法 查看\创建\使用\删除\清空\修改 数据库表(是否可空,默认值,主键,自增,外键) 表内容的增删改查 where条件.通配符_%. ...
- phper:敢问路在何方
很多php程序员存在未来发展方面的困扰,介于各方面的因素,phper 比其他程序员更容易遇到上升天花板. 一方面,一般只有初创企业为了快速实现产品上市以及极容易招到 phper 才使用 php 来实现 ...
- 【Linux题目】第六关
[定时任务规则] 1. 如果在某用户的crontab文件中有以下记录,该行中的命令多久执行一次(RHCE考试题)?( ) 30 4 * * 3 mycmd A. 每小时. B. 每周. C. 每年三月 ...
- mac OS npm 安装/卸载失败 权限问题解决方案
在终端输入 sudo chown -R $USER /usr/local 输入开机密码
- 如何理解Java的值传递
结论 为了加深印象,先把结论放在文章开头. ++Java中只有值传递++. 形参与实参 在理解Java的值传递 实参Argument 实际参数,主调用函数传递给调用函数的参数 形参Parameter ...
- #Week7 Neural Networks : Learning
一.Cost Function and Backpropagation 神经网络的损失函数: \[J(\Theta) = - \frac{1}{m} \sum_{i=1}^m \sum_{k=1}^K ...
- 图论--2-SAT--HDU/HDOJ 1814 Peaceful Commission
Peaceful Commission Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Oth ...
- CodeForces - 260B
A recently found Ancient Prophesy is believed to contain the exact Apocalypse date. The prophesy is ...
- 线段树的区间合并 B - LCIS
B - LCIS HDU - 3308 这个是一个很简单很明显的线段树的区间合并,不过区间合并的题目都还是有点难写,建议存个板子. #include <cstdio> #include & ...