转载自https://blog.csdn.net/vic_fang/article/details/24653477

————————————————————————————————————————————————————

在日常开发中,我们经常会碰到这样的情况:一些异步请求我们需要等到接收到请求后再执行下一步动作,这时我们就需要把异步动作转为同步动作。

java中给我们提供了一个CountDownLatch类来实现这个功能。

先看下CountDownLatch的官方定义:

A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.

意思是:CountDownLatch是一个同步助手,它可以使一个或多个线程等待,直到一系列在其他线程中执行的动作完成(这些线程才被唤醒)

具体如何使用呢?

看下这段文档:

CountDownLatch is initialized with a givencount. Theawait() methods block until the current count reaches zero due to invocations of the countDown() method, after which all waiting threads are released and any subsequent invocations ofawait() return immediately. 

A useful property of aCountDownLatch is that it doesn't require that threads callingcountDown wait for the count to reach zero before proceeding, it simply prevents any thread from proceeding past anawait() until all threads could pass. 

这句翻译出来会有偏差,大家自己体会吧

详细用例:

[java] view plain copy

  1. class Driver { // ...
  2. void main() throws InterruptedException {
  3. CountDownLatch startSignal = new CountDownLatch(1);
  4. CountDownLatch doneSignal = new CountDownLatch(N);
  5. for (int i = 0; i < N; ++i) // create and start threads
  6. new Thread(new Worker(startSignal, doneSignal)).start();
  7. doSomethingElse();            // don't let run yet
  8. startSignal.countDown();      // let all threads proceed
  9. doSomethingElse();
  10. doneSignal.await();           // wait for all to finish
  11. }
  12. class Worker implements Runnable {
  13. private final CountDownLatch startSignal;
  14. private final CountDownLatch doneSignal;
  15. Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {
  16. this.startSignal = startSignal;
  17. this.doneSignal = doneSignal;
  18. }
  19. public void run() {
  20. try {
  21. startSignal.await();
  22. doWork();
  23. doneSignal.countDown();
  24. catch (InterruptedException ex) {} // return;
  25. }
  26. void doWork() { ... }
  27. }
  28. }

——————————————————————-—————————————————————————————

最近项目在执行过程中,有多个 独立模块 异步执行,将执行结果统一处理后返回,代码可以顺序调用各个模块执行,然后统一处理,但是效率过低,考虑采用多线程异步处理,但异步执行提交任务后就顺序执行其他代码了,无法统一获取各模块处理结果。采用countDownLatch可以等待所有异步线程执行完成再统一处理。

  • countDownLatch jdk里描述 
    A synchronization aid that allows one or more threads to wait until 
    a set of operations being performed in other threads completes. 
    一个允许等待一个或多个其它线程执行完成的同步助手 
    使用场景: 
    1.等待一个或多个线程完成再执行其它操作 
    2.等待一个线程执行多次再执行其它操作 
  • countDownLatch实现原理
private final Sync sync;
public CountDownLatch(int count) {if (count < 0) throw new IllegalArgumentException("count < 0");this.sync = new Sync(count);}
初始化时将任务个数传递给同步控制器Sync,每次调用countDown方法,开始执行异步任务,Sync释放一个资源
public void countDown() {sync.releaseShared(1);}调用await,await方法判断Sycn的状态,如果Sync状态显示未执行完成,则继续分配资源执行。
当countDown为0时,统一返回异步结果。
  • 代码示例
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;public class MultiJobExecutors {private CountDownLatch countDownLatch;private List<Task> tasks;private  static ExecutorService executor = null;public MultiJobExecutors(List<Task> tasks) {countDownLatch = new CountDownLatch(tasks.size());executor = Executors.newFixedThreadPool(tasks.size());this.tasks = tasks;}public void execute() {if (tasks == null|| tasks.isEmpty()) {return;}for (int i=0;i< tasks.size();i++) {executor.submit(new Job(countDownLatch,tasks.get(i)));System.out.println("xx"+i);}try {//等待所有线程结束countDownLatch.await(15, TimeUnit.SECONDS);//执行其他操作System.out.println("it's over");//关闭线程池executor.shutdown();} catch (InterruptedException e) {e.printStackTrace();}}private class Job implements Callable<Object>{private CountDownLatch latch;private Task task;public Job(CountDownLatch latch, Task task) {this.latch = latch;this.task = task;}@Overridepublic Object call() throws Exception {System.out.println(System.currentTimeMillis());//执行线程task.execute();//countDown自减latch.countDown();return null;}}private static class Task{private String str;public Task(String str) {this.str = str;}public void execute(){System.out.println(str);}}public static void main(String[] args) {Task task = new Task("I");Task task1 = new Task("love");Task task2 = new Task("you");Task task3 = new Task(",");Task task4 = new Task("its");Task task5 = new Task("not");Task task6 = new Task("true");List<Task> tasks = new ArrayList<Task>();tasks.add(task);tasks.add(task1);tasks.add(task2);tasks.add(task3);tasks.add(task4);tasks.add(task5);tasks.add(task6);MultiJobExecutors multiJobExecutors = new MultiJobExecutors(tasks);multiJobExecutors.execute();}
}
  • 执行结果
xx0
1472706027197
I
xx1
1472706027197
love
xx2
1472706027197
you
xx3
1472706027197
,
xx4
1472706027197
its
xx5
1472706027198
not
xx6
1472706027198
true
it's over

CountDownLatch的概念

CountDownLatch是一个同步工具类,用来协调多个线程之间的同步,或者说起到线程之间的通信(而不是用作互斥的作用)。

CountDownLatch能够使一个线程在等待另外一些线程完成各自工作之后,再继续执行。使用一个计数器进行实现。计数器初始值为线程的数量。当每一个线程完成自己任务后,计数器的值就会减一。当计数器的值为0时,表示所有的线程都已经完成了任务,然后在CountDownLatch上等待的线程就可以恢复执行任务。

CountDownLatch的用法

CountDownLatch典型用法1:某一线程在开始运行前等待n个线程执行完毕。将CountDownLatch的计数器初始化为n new CountDownLatch(n) ,每当一个任务线程执行完毕,就将计数器减1 countdownlatch.countDown(),当计数器的值变为0时,在CountDownLatch上 await() 的线程就会被唤醒。一个典型应用场景就是启动一个服务时,主线程需要等待多个组件加载完毕,之后再继续执行。

CountDownLatch典型用法2:实现多个线程开始执行任务的最大并行性。注意是并行性,不是并发,强调的是多个线程在某一时刻同时开始执行。类似于赛跑,将多个线程放到起点,等待发令枪响,然后同时开跑。做法是初始化一个共享的CountDownLatch(1),将其计数器初始化为1,多个线程在开始执行任务前首先 coundownlatch.await(),当主线程调用 countDown() 时,计数器变为0,多个线程同时被唤醒。

CountDownLatch的不足

CountDownLatch是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当CountDownLatch使用完毕后,它不能再次被使用。

参考资料:http://www.importnew.com/15731.html

多线程编程--异步转同步之CountDownLatch相关推荐

  1. Linux多线程编程---线程间同步(互斥锁、条件变量、信号量和读写锁)

    本篇博文转自http://zhangxiaoya.github.io/2015/05/15/multi-thread-of-c-program-language-on-linux/ Linux下提供了 ...

  2. Win32多线程编程(3) — 线程同步与通信

    一.线程间数据通信 系统从进程的地址空间中分配内存给线程栈使用.新线程与创建它的线程在相同的进程上下文中运行.因此,新线程可以访问进程内核对象的所有句柄.进程中的所有内存以及同一个进程中其他所有线程的 ...

  3. 多线程编程、线程同步|安全和线程通信

    多线程编程 多线程的优势 线程在程序中是独立的.并发的执行流,与分隔的进程相比,进程中的线程之间的隔离程度要小.他们共享内存.文件句柄和其他每个进程应有的状态. 因为线程的划分尺度小于进程,使得多线程 ...

  4. java多线程同步与死锁,廖雪峰Java11多线程编程-2线程同步-3死锁

    在多线程编程中,要执行synchronized块,必须首先获得指定对象的锁. 1.Java的线程锁是可重入的锁 public void add(int m){ synchronized (lock){ ...

  5. ASP.NET温故而知新学习系列之ASP.NET多线程编程—异步编程(九)

    阅读目录 一:同步处理 二:异步处理 三:异步委托 四:通过委托同步调用方法 五:通过委托异步调用方法 一:同步处理 一个同步操作会阻塞整个当前的进程,直到这个操作完成才能执行下一段代码 二:异步处理 ...

  6. python多线程编程(6): 队列同步

    From: http://www.cnblogs.com/holbrook/archive/2012/03/15/2398060.html 前面介绍了互斥锁和条件变量解决线程间的同步问题,并使用条件变 ...

  7. Linux 多线程 - 线程异步与同步机制

    I. 同步机制 线程间的同步机制主要包括三个: 互斥锁: 以排他的方式,防止共享资源被并发访问: 互斥锁为二元变量, 状态为0-开锁.1-上锁; 开锁必须由上锁的线程执行,不受其它线程干扰. 条件变量 ...

  8. iOS多线程编程:线程同步总结 NSCondtion

    1:原子操作 - OSAtomic系列函数 iOS平台下的原子操作函数都以OSAtomic开头,使用时需要包含头文件<libkern/OSBase.h>.不同线程如果通过原子操作函数对同一 ...

  9. python多线程编程: 条件变量同步

    2019独角兽企业重金招聘Python工程师标准>>> 有待写.............................哈哈 转载于:https://my.oschina.net/0 ...

最新文章

  1. swift中单例的创建及销毁
  2. 【python】 针对python3 下无法导入tkinter
  3. 双线性插值算法ARM NEON优化
  4. 廖雪峰python教程菜鸟变高手_python怎样
  5. nssl1195-健美猫【???】
  6. 小数前的0在html不显示,jsp小数显示问题 例如 我在oracle 数据库中查询出来的是 0.01 但是在jsp页面上就显示成 .01 没有前面的0...
  7. node重命名文件名_node文件批量重命名
  8. 余姚计算机编程培训,余姚编程软件培训
  9. [乐意黎原创]PHP 老司机指南
  10. 随风摇曳的她——美蕨(matlab实现)
  11. 要不要考公务员 | 进国企?
  12. 自动化测试环境搭建之RFS自动化测试框架全攻略
  13. Zeppelin上通过Spark读写mysql数据库
  14. 服务器自带ddos工具,详解DDoS工具 一款流行DDoS木马工具
  15. 【图像处理】获取图片像素点
  16. opencv 入门笔记五 padding(图像加边框)
  17. 选对平台 ... 选对平台... 选对平台 ...
  18. 如何使用Java对密码进行加密 Java Sah加密方式帮你实现加密
  19. Uniapp中onShow()的应用
  20. 【论文写作】Endnote插入参考文献对应的英文期刊名全称如何修改为缩写形式(内附最新Endnote参考文献期刊名26627种全称和对应缩写表)

热门文章

  1. 感染性的木马病毒分析之样本KWSUpreport.exe
  2. 在VC中如何找到崩溃的源头
  3. PostgreSQL学习笔记4之常用数据类型
  4. DDoS攻击原理及防护方法论
  5. GROUP BY 子句中 选择列表中的列无效,因为该列没有包含在聚合函数或
  6. vector的reserve和resize
  7. 记一次失败的Windows环境编译Nginx源码
  8. 为什么将0.1f改为0会使性能降低10倍?
  9. Qt下Tcp传输文件
  10. IO多路转接之poll