博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[笔记][Java7并发编程实战手冊]3.4 等待多个并发事件的完毕CountDownLatch倒计数闭锁...
阅读量:6281 次
发布时间:2019-06-22

本文共 3786 字,大约阅读时间需要 12 分钟。


简单介绍

本文学习CountDownLatch 倒计数闭锁。

本人英文不好。靠机器翻译,然后有一段非常形象的描写叙述,让我把它叫为倒计数

用给定的计数 初始化 CountDownLatch。由于调用了 countDown() 方法。所以在当前计数到达零之前。await 方法会一直受堵塞。

之后,会释放全部等待的线程,await 的全部兴许调用都将马上返回。这样的现象仅仅出现一次——计数无法被重置。 - jdk1.6里面的文档

能够看出,是由于会倒计数。并且计数器到0之后, 就不能再次使用该对象了(自断后路)。所以称为倒计数闭锁


CountDownLatch

是一个同步辅助类,在完毕一组正在其它线程中执行的操作之前,它同意一个或多个线程一直等待。

假如说:有a、b、c 三个线程。c 须要a,b线程的结果,所以C 须要等待 a,b 线程都执行完了,b 才干拿到正确的结果。 就是该类的一个使用场景

  1. countDown() 来计数(计时)
  2. await() 创建屏障点。等待计数到0的时候,await()方法后面的代码才执行。(换句话说。计数线程一起冲破这个屏障)
  3. getCount(): 是获取当前计数,不是总数
  4. 是辅助类! 不保证同步。

原理:

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个工匠线程把龙珠镶嵌完毕后,密室被打开,守卫也复活,得到了我们想要的正确结果

转载地址:http://jgnva.baihongyu.com/

你可能感兴趣的文章
Python 数据类型
查看>>
iOS--环信集成并修改头像和昵称(需要自己的服务器)
查看>>
PHP版微信权限验证配置,音频文件下载,FFmpeg转码,上传OSS和删除转存服务器本地文件...
查看>>
教程前言 - 回归宣言
查看>>
PHP 7.1是否支持操作符重载?
查看>>
Vue.js 中v-for和v-if一起使用,来判断select中的option为选中项
查看>>
Java中AES加密解密以及签名校验
查看>>
定义内部类 继承 AsyncTask 来实现异步网络请求
查看>>
VC中怎么读取.txt文件
查看>>
如何清理mac系统垃圾
查看>>
企业中最佳虚拟机软件应用程序—Parallels Deskto
查看>>
Nginx配置文件详细说明
查看>>
怎么用Navicat Premium图标编辑器创建表
查看>>
Spring配置文件(2)配置方式
查看>>
MariaDB/Mysql 批量插入 批量更新
查看>>
ItelliJ IDEA开发工具使用—创建一个web项目
查看>>
solr-4.10.4部署到tomcat6
查看>>
切片键(Shard Keys)
查看>>
淘宝API-类目
查看>>
virtualbox 笔记
查看>>