1.基本概念

CountDownLatch,中文名倒数闩,jdk并发工具包中一个并发控制器,它抽象了一个常见的多线程并发场景,开发人员使用它可以写出同时兼顾线程安全性与高效率的代码。

2.抽象模型

相当于是一种进化版本的等待/通知机制,它可以的实现的是一个或多个工作线程完成任务后通知一个或多个等待线程开始工作,jdk中的await/notify、notifyAll是一个工作线程完成任务通知一个等待线程或所有等待的线程。

3.使用场景

运动员田径跑步比赛

4.CountDownLatch使用api

<1>CountDownLatch latch = new CountDownLatch(n); //初始化倒数闩

<2>latch.await()或latch.await(long timeout,TimeUnit unit); //执行线程等待,直到latch倒数为0(超时后中断或线程被中断)

<3>latch.countDown(); //执行线程把latch倒数数减1,直到为0,会通知所有被这个计数器阻塞的线程;如果当前计数器latch为0,调用countDown(),不会继续减1;

5.使用示例(田径比赛)

  1. public static void main(String[] args) throws InterruptedException {
  2. CountDownLatch beginLatch = new CountDownLatch(1); // 起跑倒数闩
  3. CountDownLatch endLatch = new CountDownLatch(10); // 结束倒数闩
  4. // 创建10个线程,代表是个运动员,他们的主要任务就是预备准备、和跑步两个阶段
  5. ExecutorService executor = Executors.newFixedThreadPool(10);
  6. for (int i = 1; i < 11; i++) {
  7. final int num = i;
  8. Runnable runnable = new Runnable() {
  9. @Override
  10. public void run() {
  11. try {
  12. // 准备阶段
  13. long a = (long) (Math.random() * 1000);
  14. Thread.sleep(a);
  15. System.out.println("运动员" + num +"号,准备了" + a + "s,准备完毕!");
  16. beginLatch.await();
  17. // 跑步阶段
  18. long b = (long) (Math.random() * 100);
  19. Thread.sleep(b);
  20. System.out.println("运动员" + num + "号,用时" + b + "s,完成比赛");
  21. endLatch.countDown();
  22. } catch (InterruptedException e) {
  23. // TODO Auto-generated catch block
  24. e.printStackTrace();
  25. }
  26. }
  27. };
  28. executor.submit(runnable);
  29. }
  30. //出发信号发出
  31. beginLatch.countDown();
  32. endLatch.await();
  33. System.out.println("跑步结束");
  34. }

细心的你会发现上述的代码存在致命的错误就是当主线程发出了开跑信号beginLatch.countDown(),可能有部分运动员还在准备。运行结果如下:

  1. 运动员10号,准备了155s,准备完毕!
  2. 运动员10号,用时31s,完成比赛
  3. 运动员8号,准备了228s,准备完毕!
  4. 运动员8号,用时61s,完成比赛
  5. 运动员9号,准备了333s,准备完毕!
  6. 运动员3号,准备了335s,准备完毕!
  7. 运动员9号,用时61s,完成比赛
  8. 运动员3号,用时94s,完成比赛
  9. 运动员4号,准备了513s,准备完毕!
  10. 运动员4号,用时71s,完成比赛
  11. 运动员2号,准备了598s,准备完毕!
  12. 运动员6号,准备了616s,准备完毕!
  13. 运动员6号,用时39s,完成比赛
  14. 运动员2号,用时54s,完成比赛
  15. 运动员1号,准备了737s,准备完毕!
  16. 运动员5号,准备了805s,准备完毕!
  17. 运动员1号,用时80s,完成比赛
  18. 运动员5号,用时70s,完成比赛
  19. 运动员7号,准备了923s,准备完毕!
  20. 运动员7号,用时67s,完成比赛
  21. 跑步结束
  22. 没有都准备好就开始,控制不合理

根本原因在于这里缺少一个倒数闩,来计数准备好的运动员。我们进行改进如下

  1. public static void main(String[] args) throws InterruptedException {
  2. CountDownLatch readyLatch = new CountDownLatch(10); //准备好倒数闩
  3. CountDownLatch beginLatch = new CountDownLatch(1); // 起跑倒数闩
  4. CountDownLatch endLatch = new CountDownLatch(10); // 结束倒数闩
  5. // 创建10个线程,代表是个运动员,他们的主要任务就是预备准备、和跑步两个阶段
  6. ExecutorService executor = Executors.newFixedThreadPool(10);
  7. for (int i = 1; i < 11; i++) {
  8. final int num = i;
  9. Runnable runnable = new Runnable() {
  10. @Override
  11. public void run() {
  12. try {
  13. // 准备阶段
  14. long a = (long) (Math.random() * 1000);
  15. Thread.sleep(a);
  16. System.out.println("运动员" + num +"号,准备了" + a + "s,准备完毕!");
  17. readyLatch.countDown();
  18. beginLatch.await();
  19. // 跑步阶段
  20. long b = (long) (Math.random() * 100);
  21. Thread.sleep(b);
  22. System.out.println("运动员" + num + "号,用时" + b + "s,完成比赛");
  23. endLatch.countDown();
  24. } catch (InterruptedException e) {
  25. // TODO Auto-generated catch block
  26. e.printStackTrace();
  27. }
  28. }
  29. };
  30. executor.submit(runnable);
  31. }
  32. readyLatch.await();
  33. //出发信号发出
  34. beginLatch.countDown();
  35. endLatch.await();
  36. System.out.println("跑步结束");
  37. }

改进后运行结果

  1. 运动员8号,准备了112s,准备完毕!
  2. 运动员3号,准备了119s,准备完毕!
  3. 运动员5号,准备了463s,准备完毕!
  4. 运动员6号,准备了579s,准备完毕!
  5. 运动员2号,准备了597s,准备完毕!
  6. 运动员1号,准备了825s,准备完毕!
  7. 运动员7号,准备了849s,准备完毕!
  8. 运动员9号,准备了876s,准备完毕!
  9. 运动员4号,准备了931s,准备完毕!
  10. 运动员10号,准备了930s,准备完毕!
  11. 运动员6号,用时0s,完成比赛
  12. 运动员5号,用时19s,完成比赛
  13. 运动员9号,用时24s,完成比赛
  14. 运动员8号,用时56s,完成比赛
  15. 运动员3号,用时62s,完成比赛
  16. 运动员1号,用时77s,完成比赛
  17. 运动员7号,用时84s,完成比赛
  18. 运动员4号,用时85s,完成比赛
  19. 运动员2号,用时88s,完成比赛
  20. 运动员10号,用时86s,完成比赛
  21. 跑步结束

Java核心-多线程-并发控制器-CountDownLatch倒数闩的更多相关文章

  1. Java核心-多线程-并发控制器-Semaphore信号量

    Semaphore是非常有用的一个多线程并发控制组件(Java还有CountDownLatch.CyclicBarrier.Exchanger多线程组件),它相当于是一个并发控制器,是用于管理信号量的 ...

  2. Java核心-多线程-并发控制器-CyclicBarrier同步屏障

    1.基本概念 中文译本同步屏障,同样来自jdk并发工具包中一个并发控制器,它的使用和CountDownLatch有点相似,能够完成某些相同并发场景,但是它们却不相同. 2.抽象模型 主要用来实现多个线 ...

  3. Java核心-多线程-并发控制器-Exchanger交换器

    1.基本概念 Exchanger,从名字上理解就是交换.Exchanger用于在两个线程之间进行数据交换,注意也只能在两个线程之间进行数据交换. 线程会阻塞在Exchanger的exchange方法上 ...

  4. java核心-多线程-Java多线程编程涉及到包、类

    Java有关多线程编程设计的类主要涉及两个包java.lang和java.util.concurrent两个包 java.lang包,主要是线程基础类 <1>Thread <2> ...

  5. Java接口多线程并发测试 (一)

    本文为作者原创,禁止转载,违者必究法律责任!!! 本文为作者原创,禁止转载,违者必究法律责任!!! Java接口多线程并发测试 一,首先写一个接口post 请求代码: import org.apach ...

  6. java核心-多线程(1)-知识大纲

    Thread,整理一份多线程知识大纲,大写意 1.概念介绍 线程 进程 并发 2.基础知识介绍 Java线程类 Thread 静态方法&实例方法 Runnable Callable Futur ...

  7. java核心-多线程(8)- 并发原子类

        使用锁能解决并发时线程安全性,但锁的代价比较大,而且降低性能.有些时候可以使用原子类(juc-atomic包中的原子类).还有一些其他的非加锁式并发处理方式,我写这篇文章来源于Java中有哪些 ...

  8. Java中多线程并发体系知识点汇总

    一.多线程 1.操作系统有两个容易混淆的概念,进程和线程. 进程:一个计算机程序的运行实例,包含了需要执行的指令:有自己的独立地址空间,包含程序内容和数据:不同进程的地址空间是互相隔离的:进程拥有各种 ...

  9. [Java复习] 多线程&并发 知识点补充

    0. wait/notify/notifyAll的理解? wait:让持有该对象锁的线程等待: notify: 唤醒任何一个持有该对象锁的线程: notifyAll: 唤醒所有持有该对象锁的线程: 它 ...

随机推荐

  1. C# 延迟函数

    #region 延迟函数 public static bool Delay(int delayTime) { DateTime now = DateTime.Now; int s; do { Time ...

  2. final发布用户使用报告

    用户数量:13人 姓名如下(包括化名):张小斌.王瑞瑞.蛋蛋.小美.晨曦.小丽.张利刚.小闫.小谢.小崔.小欢欢.小胡胡.小霞霞 寻找的用户多为王者荣耀交流协会成员的同学,对PSP Daily软件有极 ...

  3. 【Coucurrency-CountDownLatch】-20161203-0002

    简介 java异步任务相关的工具.主要用在某些线程需要等到其他线程完成某些操作后才能执行的场景. 等待线程需要显示的调用wait方法,表示线程当前挂起,需要等到countdownLatch到0才执行. ...

  4. git教程:管理修改

    转载:管理修改 现在,假定你已经完全掌握了暂存区的概念.下面,我们要讨论的就是,为什么Git比其他版本控制系统设计得优秀,因为Git跟踪并管理的是修改,而非文件. 你会问,什么是修改?比如你新增了一行 ...

  5. VS2010与Matlab2010b混合编程

    环境: 1.VS2010 2.MATLAB 2010b 3.WINDOW 7 (X64) 1.Matlab环境设置 要建立独立运行的C应用程序,系统中需要安装Matlab.Matlab编译器.C/C+ ...

  6. sqlalchemy执行sql语句

    #删除user表中的所有数据,表中的自增字段又从默认值开始 session.execute("truncate table user")

  7. WEB测试专题之测试分类

    虽然说是一个功能测试就概括了,但是其实这里面还别有洞天,大概区分为下面几个小类别:WEB测试专题之web测试分类一(1)链接测试链接是Web应用系统的一个主要特征,它是在页面之间切换和指导用户去一些不 ...

  8. 1945 : 卡贩子Carol

    题目描述 来自F星球的Carol是一个不折不扣的“正版游戏受害者”,在黑色星期五的疯狂购买后,钱包渐空的Carol突然发现TA所使用的游戏交易平台上有个值得留意的地方————集换式卡牌. 集换式卡牌是 ...

  9. 我的代码-random forest

    # coding: utf-8 # In[1]: import pandas as pdimport numpy as npfrom sklearn import treefrom sklearn.s ...

  10. 在Windows下通过压缩包方式安装MySQL

    需求:下载MySQL有两种方法,一是下载可执行文件,通过点点点的方式,比较简单没什么技术含量,但是之前通过此方法下载的MySQL与Python进行连接交互的时候总是报1045错误,一直没找到原因,尝试 ...