CountDownLatch介绍

CountDownLatch概述

  1. CountDownLatch一般用作多线程倒计时计数器,强制它们等待其他一组(CountDownLatch的初始化决定)任务执行完成。
  2. 有一点要说明的是CountDownLatch初始化后计数器值递减到0的时候,不能再复原的,这一点区别于SemaphoreSemaphore是可以通过release操作恢复信号量的。

CountDownLatch使用原理

使用原理

  1. 创建CountDownLatch并设置计数器值。
  2. 启动多线程并且调用CountDownLatch实例的countDown()方法。
  3. 主线程调用 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

从运行结果可以看出:

  1. 主线程先打印do something else 1do something else 2。因为startSignal.countDown();完后,count才为0,子线程才能打印。
  2. 因为startSignal.await();是在子线程内,所有子线程都等待startSignal.countDown()执行后才能打印do work!
  3. 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使用详解的更多相关文章

  1. 最强Java并发编程详解:知识点梳理,BAT面试题等

    本文原创更多内容可以参考: Java 全栈知识体系.如需转载请说明原处. 知识体系系统性梳理 Java 并发之基础 A. Java进阶 - Java 并发之基础:首先全局的了解并发的知识体系,同时了解 ...

  2. Java 字符串格式化详解

    Java 字符串格式化详解 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 文中如有纰漏,欢迎大家留言指出. 在 Java 的 String 类中,可以使用 format() 方法 ...

  3. Java 序列化Serializable详解

    Java 序列化Serializable详解(附详细例子) Java 序列化Serializable详解(附详细例子) 1.什么是序列化和反序列化Serialization(序列化)是一种将对象以一连 ...

  4. Java String类详解

    Java String类详解 Java字符串类(java.lang.String)是Java中使用最多的类,也是最为特殊的一个类,很多时候,我们对它既熟悉又陌生. 类结构: public final ...

  5. 最新java数组的详解

    java中HashMap详解 http://alex09.iteye.com/blog/539545 总结: 1.就像引用类型的数组一样,当我们把 Java 对象放入数组之时,并不是真正的把 Java ...

  6. JAVA IO 类库详解

    JAVA IO类库详解 一.InputStream类 1.表示字节输入流的所有类的超类,是一个抽象类. 2.类的方法 方法 参数 功能详述 InputStream 构造方法 available 如果用 ...

  7. 转:Java HashMap实现详解

    Java HashMap实现详解 转:http://beyond99.blog.51cto.com/1469451/429789 1.    HashMap概述:    HashMap是基于哈希表的M ...

  8. 淘宝JAVA中间件Diamond详解(2)-原理介绍

    淘宝JAVA中间件Diamond详解(二)---原理介绍 大家好,通过第一篇的快速使用,大家已经对diamond有了一个基本的了解.本次为大家带来的是diamond核心原理的介绍,主要包括server ...

  9. 【转】 java中HashMap详解

    原文网址:http://blog.csdn.net/caihaijiang/article/details/6280251 java中HashMap详解 HashMap 和 HashSet 是 Jav ...

随机推荐

  1. all_user_func()详解

    来源:https://blog.csdn.net/moliyiran/article/details/83514495 call_user_func — 把第一个参数作为回调函数调用 通过函数的方式回 ...

  2. vue显示富文本

    来源:https://segmentfault.com/q/1010000013952512 用  v-html 属性解决

  3. 手把手编写自己的PHP MVC框架实例教程

    1 什么是MVC MVC模式(Model-View-Controller)是软件工程中的一种软件架构模式. MVC把软件系统分为三个基本部分:模型(Model).视图(View)和控制器(Contro ...

  4. 矩阵类的代码(C++)

    The Codes of Matrix Class Matrix.h:#ifndef MATRIX_H#define MATRIX_H #include<iostream> #includ ...

  5. Maven Wrapper简介

    文章目录 简介 Maven Wrapper的结构 下载Maven Wrapper 使用 Maven Wrapper简介 简介 开发java项目少不了要用到maven或者gradle,对比gradle而 ...

  6. java1-3总结 19201421-吴志越

    关于最近几次作业,从C语言到Java的过渡,也就是从面向过程到面向对象的过渡.其中,一共有三次作业,前俩次可能更加偏向于过程的设计,利用C语言的想法就可以完成,但是,从需要使用类的开始,就逐渐向对象偏 ...

  7. 【React踩坑记五】React项目中引入并使用react-ace代码编辑插件(自定义列表提示)

    最近有一个引入sql编辑器插件的需求,要求代码高亮显示,代码智能提示,以及支持自定义代码提示列表等功能.中途在自定义代码提示列表中由于没有相关demo,所以踩了一些坑,遂将其整理如下,以便日后查看. ...

  8. vim的四种工作模式(转载别人的)

    Vim操作的四种模式 Vim的四种模式一.启动Vim1.双击桌面的图标,就可以启动Vim(是图形界面的)2.在开始菜单---点--运行 接着输入 vim 或者gvim,就可以启动Vim或Gvim了.二 ...

  9. linux服务器(CentOS)一键安装express框架

    express框架需要nodejs环境支持,没有安装node.js环境的同学可以参照下面这篇博客 linux服务器安装配置Node.js 好了,言归正传.先使用xshell或者其它软件连接我们的服务器 ...

  10. [开发笔记]-unix时间戳、GMT时间与datetime类型时间之前的转换

    前段时间项目中涉及到了MySql和MsSql数据类型之间的转换,最近又在研究新浪微博的API,涉及到了带有时区的GMT时间类型的转换,所以,特记录于此,以备日后查询. 一:UNIX时间戳与dateti ...