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.使用示例(田径比赛)

    public static void main(String[] args) throws InterruptedException {
CountDownLatch beginLatch = new CountDownLatch(1); // 起跑倒数闩
CountDownLatch endLatch = new CountDownLatch(10); // 结束倒数闩 // 创建10个线程,代表是个运动员,他们的主要任务就是预备准备、和跑步两个阶段
ExecutorService executor = Executors.newFixedThreadPool(10);
for (int i = 1; i < 11; i++) {
final int num = i;
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
// 准备阶段
long a = (long) (Math.random() * 1000);
Thread.sleep(a);
System.out.println("运动员" + num +"号,准备了" + a + "s,准备完毕!");
beginLatch.await();
// 跑步阶段
long b = (long) (Math.random() * 100);
Thread.sleep(b);
System.out.println("运动员" + num + "号,用时" + b + "s,完成比赛");
endLatch.countDown(); } catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
executor.submit(runnable);
}
//出发信号发出
beginLatch.countDown();
endLatch.await();
System.out.println("跑步结束");
}

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

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

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

    public static void main(String[] args) throws InterruptedException {
CountDownLatch readyLatch = new CountDownLatch(10); //准备好倒数闩
CountDownLatch beginLatch = new CountDownLatch(1); // 起跑倒数闩
CountDownLatch endLatch = new CountDownLatch(10); // 结束倒数闩 // 创建10个线程,代表是个运动员,他们的主要任务就是预备准备、和跑步两个阶段
ExecutorService executor = Executors.newFixedThreadPool(10);
for (int i = 1; i < 11; i++) {
final int num = i;
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
// 准备阶段
long a = (long) (Math.random() * 1000);
Thread.sleep(a);
System.out.println("运动员" + num +"号,准备了" + a + "s,准备完毕!");
readyLatch.countDown();
beginLatch.await();
// 跑步阶段
long b = (long) (Math.random() * 100);
Thread.sleep(b);
System.out.println("运动员" + num + "号,用时" + b + "s,完成比赛");
endLatch.countDown(); } catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
executor.submit(runnable);
}
readyLatch.await();
//出发信号发出
beginLatch.countDown();
endLatch.await();
System.out.println("跑步结束");
}

改进后运行结果

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

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. python_01

    测试工程师的短板,近二年的时间,python这门语言获得非同一般的美誉.在算法,测试,运维里火的不要不要的.本人学了将近一年的时间,总是林林散散的学,也没有规划的去分析和总结.希望能够帮我梳理一下这一 ...

  2. 开发H5页面遇到的问题以及解决

    1.第一个问题就是规范问题,现在边注释边编程以及语义化命名的问题已经基本的改善,页面的层级结构设计也条理了许多,现在的问题就是我对于页面的更深的应用还不够,比如我知道文档流自上而下从左至右,写在下面的 ...

  3. 正则表达式andJS内存空间详细图解

    http://www.runoob.com/js/js-regexp.html https://blog.csdn.net/pingfan592/article/details/55189622

  4. where 常用条件范例

    where() public method Sets the WHERE part of the query. The method requires a $condition parameter, ...

  5. 【leetcode】485. Max Consecutive Ones

    problem 485. Max Consecutive Ones solution1: class Solution { public: int findMaxConsecutiveOnes(vec ...

  6. 关于rabbitmq的介绍

    原文转载:http://blog.csdn.net/whycold/article/details/41119807 保护原帖,尊重技术,致敬工匠! 一.简介 MQ全称为Message Queue, ...

  7. web过滤器

    Filter也称之为过滤器,它是Servlet技术中比较激动人心的技术,WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态 ht ...

  8. JS如何充分“压榨”浏览器

    不同浏览器厂商实现的 JS 标准有所不同,这意味着 window 对象和可用的 api 也有所不同,希望不久的将来,所有浏览器都能实现统一的 JS 标准. 自己写 api 是很耗费时间跟精力的,而且变 ...

  9. What is the Annotation?

    Annotation称为注释或注解,它是一个接口.注解提供了一种为程序元素(类.方法.成员变量等)设置元数据(描述其它数据的数据)的方法.编译器.开发工具或其它程序中可以通过反射来获取程序中的Anno ...

  10. javascript---lat const var 的区别

    首先,ECMAScript和JavaScript关系:      ECMAScript是一个国际通过的标准化脚本语言.JavaScript由ECMAScript和DOM.BOM三者组成.可以简单理解为 ...