Java核心-多线程-并发控制器-CountDownLatch倒数闩
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倒数闩的更多相关文章
- Java核心-多线程-并发控制器-Semaphore信号量
Semaphore是非常有用的一个多线程并发控制组件(Java还有CountDownLatch.CyclicBarrier.Exchanger多线程组件),它相当于是一个并发控制器,是用于管理信号量的 ...
- Java核心-多线程-并发控制器-CyclicBarrier同步屏障
1.基本概念 中文译本同步屏障,同样来自jdk并发工具包中一个并发控制器,它的使用和CountDownLatch有点相似,能够完成某些相同并发场景,但是它们却不相同. 2.抽象模型 主要用来实现多个线 ...
- Java核心-多线程-并发控制器-Exchanger交换器
1.基本概念 Exchanger,从名字上理解就是交换.Exchanger用于在两个线程之间进行数据交换,注意也只能在两个线程之间进行数据交换. 线程会阻塞在Exchanger的exchange方法上 ...
- java核心-多线程-Java多线程编程涉及到包、类
Java有关多线程编程设计的类主要涉及两个包java.lang和java.util.concurrent两个包 java.lang包,主要是线程基础类 <1>Thread <2> ...
- Java接口多线程并发测试 (一)
本文为作者原创,禁止转载,违者必究法律责任!!! 本文为作者原创,禁止转载,违者必究法律责任!!! Java接口多线程并发测试 一,首先写一个接口post 请求代码: import org.apach ...
- java核心-多线程(1)-知识大纲
Thread,整理一份多线程知识大纲,大写意 1.概念介绍 线程 进程 并发 2.基础知识介绍 Java线程类 Thread 静态方法&实例方法 Runnable Callable Futur ...
- java核心-多线程(8)- 并发原子类
使用锁能解决并发时线程安全性,但锁的代价比较大,而且降低性能.有些时候可以使用原子类(juc-atomic包中的原子类).还有一些其他的非加锁式并发处理方式,我写这篇文章来源于Java中有哪些 ...
- Java中多线程并发体系知识点汇总
一.多线程 1.操作系统有两个容易混淆的概念,进程和线程. 进程:一个计算机程序的运行实例,包含了需要执行的指令:有自己的独立地址空间,包含程序内容和数据:不同进程的地址空间是互相隔离的:进程拥有各种 ...
- [Java复习] 多线程&并发 知识点补充
0. wait/notify/notifyAll的理解? wait:让持有该对象锁的线程等待: notify: 唤醒任何一个持有该对象锁的线程: notifyAll: 唤醒所有持有该对象锁的线程: 它 ...
随机推荐
- easyui获取选中行上一行的数据
text: 'XX', iconCls: 'icon-ok', handler: function () { var rowI ...
- 06_mysql先分页查询再排序
数据库字段: SELECT * FROM (SELECT * FROM tb_item LIMIT 3,3) temp_table ORDER BY id DESC; 查询结果:
- VirtualBox安装Archlinux并配置桌面环境
最近无聊,就找来archlinux来玩一玩,去archlinux wiki上看了一下教程.以下是操作过程. 1. 下载镜像,下载地址; 2. 启动archlinux并选择Boot Arch Linux ...
- vue b表单
你可以用 v-model 指令在表单控件元素上创建双向数据绑定. v-model 会根据控件类型自动选取正确的方法来更新元素. 输入框 实例中演示了 input 和 textarea 元素中使用 v- ...
- 20155208徐子涵《网络对抗》Exp9 Web安全基础
20155208徐子涵<网络对抗>Exp9 Web安全基础 实验要求 本实践的目标理解常用网络攻击技术的基本原理.Webgoat实践下相关实验. 实验过程 最后一次了,没有选择尝试免考项目 ...
- Spring.NET在MVC中实现业务层和UI层解耦
最近在项目中用到了Spring.NET,使用它来实现业务层和UI层解耦.使用过程中难免遇到问题,现把遇到的一些问题整理出来,留作笔记. 使用的开发工具是vs2017,.netframework 4.6 ...
- npm,bower安装失败
安装一些软件时,总是会出现一些莫名其妙的问题.我在安装node.js时,默认安装到C:\Program Files\nodejs之后,安装bower时,bower_components默认装到C:\W ...
- 3.go语言的转译字符
go语言的转译字符 \a 匹配响铃符 (相当于 \x07) 注意:正则表达式中不能使用 \b 匹配退格符,因为 \b 被用来匹配单词边界, 可以使用 \x08 表示退格符. \f 匹配换页符 (相当于 ...
- 基于Linux-3.9.4的mykernel实验环境的极简内核分析
382 + 原创作品转载请注明出处 + https://github.com/mengning/linuxkernel/ 一.实验环境 win10 -> VMware -> Ubuntu1 ...
- React Native 开发环境搭建
1.安装 Python 2,不知道是否已支持 Python 3 2.安装 node,npm... 修改 npm 镜像,不建议使用 cnpm,cnpm 安装模块的路径与 npm 有差别 npm conf ...