[笔记][Java7并发编程实战手冊]3.4 等待多个并发事件的完毕CountDownLatch倒计数闭锁
简单介绍
本文学习CountDownLatch 倒计数闭锁。
本人英文不好。靠机器翻译,然后有一段非常形象的描写叙述,让我把它叫为倒计数
用给定的计数 初始化 CountDownLatch。由于调用了 countDown() 方法。所以在当前计数到达零之前。await 方法会一直受堵塞。
之后,会释放全部等待的线程,await 的全部兴许调用都将马上返回。这样的现象仅仅出现一次——计数无法被重置。 - jdk1.6里面的文档
能够看出,是由于会倒计数。并且计数器到0之后, 就不能再次使用该对象了(自断后路)。所以称为倒计数闭锁
CountDownLatch
是一个同步辅助类,在完毕一组正在其它线程中执行的操作之前,它同意一个或多个线程一直等待。
假如说:有a、b、c 三个线程。c 须要a,b线程的结果,所以C 须要等待 a,b 线程都执行完了,b 才干拿到正确的结果。 就是该类的一个使用场景
- countDown() 来计数(计时)
- await() 创建屏障点。等待计数到0的时候,await()方法后面的代码才执行。(换句话说。计数线程一起冲破这个屏障)
- getCount(): 是获取当前计数,不是总数
- 是辅助类! 不保证同步。
原理:
CountDownLatch是通过“共享锁”实现的。
在创建CountDownLatch中时,会传递一个int类型參数count,该參数是“锁计数器”的初始状态。表示该“共享锁”最多能被count给线程同一时候获取。当某线程调用该CountDownLatch对象的await()方法时,该线程会等待“共享锁”可用时,才干获取“共享锁”进而继续执行。而“共享锁”可用的条件,就是“锁计数器”的值为0!而“锁计数器”的初始值为count,每当一个线程调用该CountDownLatch对象的countDown()方法时,才将“锁计数器”-1。通过这样的方式。必须有count个线程调用countDown()之后,“锁计数器”才为0,而前面提到的等待线程才干继续执行。
演示样例
场景:密室大门将在七颗龙珠都被镶嵌到大门上的机关上时,密室大门才会打开。
以下的演示样例:讲述了一个密室(线程)。和7个工匠(线程)镶嵌龙珠, 最后密室大门被打开,守卫(主线程)复活的故事
/**
* Created by zhuqiang on 2015/8/19 0019.
*/
public class Client {
public static void main(String[] args) {
final CountDownLatch cd = new CountDownLatch(7); //创建辅助类7个倒计数
final Adytum adytum = new Adytum(cd);
new Thread(adytum).start();
for (int i = 0; i < 7; i++) {
new Thread(new Runnable() {
@Override
public void run() {
adytum.inlay();
}
}).start();
}
// 主线程 来模拟守卫吧。
try {
cd.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("守卫也复活了!");
}
}
//密室
class Adytum implements Runnable {
private CountDownLatch cd;
private long num = 7; // 记录剩余未被镶嵌的龙珠 ,用来对照和getCount返回的是否相等
private ReentrantLock lock = new ReentrantLock(); //创建同步锁。保证 inlay 中的资源计数 被正确计算。
public Adytum(CountDownLatch cd) {
this.cd = cd;
}
// 为密室大门服务的线程
@Override
public void run() {
System.out.println("欢迎来到密室。密室正等待被打开...");
try {
cd.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.printf("当前龙珠已镶嵌%d颗。密室被打开了!欢呼吧\n",num);
}
/**
* 镶嵌龙珠到大门上
*/
public void inlay() {
try {
lock.lock(); // 把这里的锁去掉,能看到错误的计算数据,说明了CountDownLatch:不保证同步
long count = cd.getCount(); //返回当前还剩余计数
long time = (long) (Math.random() * 10); //模拟镶嵌了多少时间
System.out.printf("%s把龙珠镶嵌到了大门上,还有%d个龙珠未被镶嵌,计数是否和getCount相等:%s,此次镶嵌耗时:%d 秒\n", Thread.currentThread().getName(), count,count==num,time);
num--;
TimeUnit.SECONDS.sleep(time); //休眠辅助类。按指定单位休眠
cd.countDown(); //锁 保证是这个临界区内的代码同步。线程相互排斥,计算的结果正确被刷到主内存中。 不是说countDown方法须要来同步
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
未加锁的某一次执行结果:
把 lock.lock(); 加锁相关的代码凝视掉。
欢迎来到密室。密室正等待被打开...
Thread-1把龙珠镶嵌到了大门上,还有7个龙珠未被镶嵌,计数是否和getCount相等:true,此次镶嵌耗时:5 秒
Thread-2把龙珠镶嵌到了大门上,还有7个龙珠未被镶嵌,计数是否和getCount相等:true,此次镶嵌耗时:2 秒
Thread-4把龙珠镶嵌到了大门上,还有7个龙珠未被镶嵌,计数是否和getCount相等:true,此次镶嵌耗时:0 秒
Thread-3把龙珠镶嵌到了大门上,还有7个龙珠未被镶嵌,计数是否和getCount相等:true,此次镶嵌耗时:1 秒
Thread-6把龙珠镶嵌到了大门上,还有7个龙珠未被镶嵌,计数是否和getCount相等:true,此次镶嵌耗时:7 秒
Thread-5把龙珠镶嵌到了大门上,还有7个龙珠未被镶嵌,计数是否和getCount相等:true,此次镶嵌耗时:9 秒
Thread-7把龙珠镶嵌到了大门上,还有7个龙珠未被镶嵌,计数是否和getCount相等:true,此次镶嵌耗时:0 秒
守卫也复活了!
当前龙珠已镶嵌0颗,密室被打开了!欢呼吧
说明:能看到错误的计算数据,全是还有7个龙珠。说明了CountDownLatch:不保证同步,仅仅是达到 让一个线程或则多个线程等待
加锁的正确结果
欢迎来到密室,密室正等待被打开...
Thread-1把龙珠镶嵌到了大门上,还有7个龙珠未被镶嵌,计数是否和getCount相等:true,此次镶嵌耗时:2 秒
Thread-2把龙珠镶嵌到了大门上,还有6个龙珠未被镶嵌,计数是否和getCount相等:true,此次镶嵌耗时:0 秒
Thread-3把龙珠镶嵌到了大门上,还有5个龙珠未被镶嵌,计数是否和getCount相等:true,此次镶嵌耗时:5 秒
Thread-4把龙珠镶嵌到了大门上,还有4个龙珠未被镶嵌,计数是否和getCount相等:true,此次镶嵌耗时:5 秒
Thread-5把龙珠镶嵌到了大门上,还有3个龙珠未被镶嵌。计数是否和getCount相等:true,此次镶嵌耗时:0 秒
Thread-6把龙珠镶嵌到了大门上,还有2个龙珠未被镶嵌。计数是否和getCount相等:true,此次镶嵌耗时:2 秒
Thread-7把龙珠镶嵌到了大门上,还有1个龙珠未被镶嵌,计数是否和getCount相等:true,此次镶嵌耗时:5 秒
当前龙珠已镶嵌0颗,密室被打开了!欢呼吧
守卫也复活了!
说明:有密室,和守卫两个线程等待7个工匠线程把龙珠镶嵌完毕后,密室被打开,守卫也复活,得到了我们想要的正确结果
[笔记][Java7并发编程实战手冊]3.4 等待多个并发事件的完毕CountDownLatch倒计数闭锁的更多相关文章
- [笔记][Java7并发编程实战手冊]系列文件夹
推荐学习多线程之前要看的书. [笔记][思维导图]读深入理解JAVA内存模型整理的思维导图文章里面的思维导图或则相应的书籍.去看一遍. 能理解为什么并发编程就会出现故障. Java7并发编程实战手冊 ...
- [笔记][Java7并发编程实战手冊]3.8 并发任务间的数据交换Exchanger
[笔记][Java7并发编程实战手冊]系列文件夹 简单介绍 Exchanger 是一个同步辅助类.用于两个并发线程之间在一个同步点进行数据交换. 同意两个线程在某一个点进行数据交换. 本章exchan ...
- 那些年读过的书《Java并发编程实战》一、构建线程安全类和并发应用程序的基础
1.线程安全的本质和线程安全的定义 (1)线程安全的本质 并发环境中,当多个线程同时操作对象状态时,如果没有统一的状态访问同步或者协同机制,不同的线程调度方式和不同的线程执行次序就会产生不同的不正确的 ...
- 【Java并发编程实战】—–synchronized
在我们的实际应用其中可能常常会遇到这样一个场景:多个线程读或者.写相同的数据,訪问相同的文件等等.对于这样的情况假设我们不加以控制,是非常easy导致错误的. 在java中,为了解决问题,引入临界区概 ...
- Java并发编程实战 05等待-通知机制和活跃性问题
Java并发编程系列 Java并发编程实战 01并发编程的Bug源头 Java并发编程实战 02Java如何解决可见性和有序性问题 Java并发编程实战 03互斥锁 解决原子性问题 Java并发编程实 ...
- 《Java7并发编程实战手册》读书笔记
一.线程管理 1.线程的创建和运行 创建线程的2种方式: 继承Thread类,并覆盖run()方法 创建一个实现Runnable接口的类.使用带参数的Thread构造器来创建Thread对象 每个Ja ...
- 《Go并发编程实战》读书笔记-语法概览
<Go并发编程实战>读书笔记-语法概览 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 本篇博客我们会快速浏览一下Go的语法,内容涉及基本构成要素(比如标识符,关键字,子 ...
- 《Go并发编程实战》读书笔记-初识Go语言
<Go并发编程实战>读书笔记-初识Go语言 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 在讲解怎样用Go语言之前,我们先介绍Go语言的特性,基础概念和标准命令. 一. ...
- 《Java并发编程实战》读书笔记一 -- 简介
<Java并发编程实战>读书笔记一 -- 简介 并发的历史 并发的历史,也是人类利用有限的资源去提高生产效率的一个的例子. 设想现在有台计算机,这台计算机具有以下的资源: 单核CPU一个 ...
随机推荐
- soapui icon以及resource的理解
https://www.soapui.org/getting-started/soapui-interface/main-window.html 以调用博客园的api为例 第一个是域名 第二个是res ...
- Swift3.0 split函数切割字符串
我们先看函数的原型: public func split(separator: Self.Iterator.Element, maxSplits: Int = default, omittingEmp ...
- P4396 [AHOI2013]作业 分块+莫队
这个题正解是莫队+树状数组,但是我个人非常不喜欢树状数组这种东西,所以决定用分块来水这个题.直接在莫队维护信息的时候,维护单点同时维护块内信息就行了. 莫队就是这几行核心代码: void add(in ...
- org.springframework.beans.factory.config.PropertyPlaceholderConfigurer的systemPropertiesModeName属性
转自:https://www.cnblogs.com/huqianliang/p/5673701.html 使用PropertyPlaceholderConfigurer类载入外部配置 在Spring ...
- day63-webservice 10.jquery的调用webservice小练习
客户端是采用jquery方式来做调用.但是这种调用,因为jquery这种调用你就得有消息体.我们得先拿到这种消息体.PersonService这个服务类有两个方法. http://localhost: ...
- 【BZOJ3218】【UOJ#77】a + b Problem
题目 题目在这里 思路&做法 明显的最小割(其实是之前做过一道类似的题) S向每一个格子连容量为\(b_i\)的边 每一个格子向T连容量为\(w_i\)的边 对于格子\(i\)向满足条件的格子 ...
- codeforces 712A. Memory and Crow
2019-05-18 08:48:27 加油,加油,坚持!!! 这道题我没有想出公式推导,只是按照模拟题来做,第5个样例超时 样例超时,方法错误 https://www.cnblogs.com/ECJ ...
- Java中利用随机数的猜拳游戏
Java中利用随机数的猜拳游戏,实现非常简单,重难点在于随机数的产生. 首先GameJude类是用于判断输赢的一个类: package testGame; public class GameJudge ...
- insert into 语句的三种写法 以及批量插入
方式1. INSERT INTO t1(field1,field2) VALUE(v001,v002); // 插入一条 方式2. INSERT INTO t1(field1,f ...
- Pop3协议详解
POP3全称为Post Office Protocol version3,即邮局协议第3版.它被用户代理用来邮件服务器取得邮件.POP3采用的也是C/S通信 模型 用户从邮件服务器上接收邮件的典型 ...