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智能提示配置

    Package Control 安装方法 1.通过快捷键 ctrl+` 或者 View > Show Console 打开控制台,然后粘贴相应的 Python 安装代码: 2.Sublime T ...

  2. 团队合作one

    一.项目介绍 为生活在长大的学生提供方快捷的生活服务,通过帖子发现自己志同道合的朋友,记录自己在长大点滴.本项目的意义在于锻炼团队的scrum能力,加强团队合作能力.确定本项目采用的技术方向:本项目整 ...

  3. jQuery-4.动画篇---淡入淡出效果

    jQuery中淡出动画fadeOut 让元素在页面不可见,常用的办法就是通过设置样式的display:none.除此之外还可以一些类似的办法可以达到这个目的.这里要提一个透明度的方法,设置元素透明度为 ...

  4. 2018-2019-2 网络对抗技术 20165228 Exp5 MSF基础应用

    2018-2019-2 网络对抗技术 20165228 Exp5 MSF基础应用 exploit选取 主动攻击:ms17_010_eternalblue(唯一) 浏览器攻击:ms05_054_onlo ...

  5. 【软件安装与环境配置】TX2安装配置caffe过程

    Tx2刷机 sudo sh ./caffe_dependency.sh 注意python的版本问题. 问题 LD -o .build_release/lib/libcaffe.so. /usr/bin ...

  6. leetcode 刷题(1)--- 两数之和

    给定一个整数数组和一个目标值,找出数组中和为目标值的两个数. 你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用. 示例: 给定 nums = [2, 7, 11, 15], target ...

  7. 简述linux操作系统启动流程

    Linux启动流程 POST-->BootSequence(BIOS)->Bootloader(MBR,grub)-->kernnel(ramdisk,initrd)-->ro ...

  8. Ubuntu18.04下make menuconfig缺少ncurses库

    kent@hu:~/work/03-kernel/linux-4.15.1$ make menuconfig *** Unable to find the ncurses libraries or t ...

  9. Python实例之抓取淘宝商品数据(json型数据)并保存为TXT

    本实例实现了抓取淘宝网中以‘python’为关键字的搜索结果,经详细查看数据存储于html文档中的js脚本中,数据类型为JSON 具体实现代码如下: import requests import re ...

  10. 18.17 U-Boot+内核移植

    18.17.1 移植U-Boot-2012.04.08 1.下载.建立source insight工程.编译.烧写.如果无运行分析原因. $ .tar.bz2 $ cd u-boot- $ make ...