「java.util.concurrent并发包」之 CountDownLatch
一 CountDownLatch是什么
二 CountDownLatch如何工作
CountDownLatch.java类中定义的构造函数:
public void CountDownLatch(int count) {...}
构造器中的计数值(count)实际上就是闭锁需要等待的线程数量。这个值只能被设置一次,而且CountDownLatch没有提供任何机制去重新设置这个计数值。
与CountDownLatch的第一次交互是主线程等待其他线程。主线程必须在启动其他线程后立即调用CountDownLatch.await()方法。这样主线程的操作就会在这个方法上阻塞,直到其他线程完成各自的任务。
其他N 个线程必须引用闭锁对象,因为他们需要通知CountDownLatch对象,他们已经完成了各自的任务。这种通知机制是通过 CountDownLatch.countDown()方法来完成的;每调用一次这个方法,在构造函数中初始化的count值就减1。所以当N个线程都调 用了这个方法,count的值等于0,然后主线程就能通过await()方法,恢复执行自己的任务。
三 在实时系统中的使用场景
- 实现最大的并行性:有时我们想同时启动多个线程,实现最大程度的并行性。例如,我们想测试一个单例类。如果我们创建一个初始计数为1的CountDownLatch,并让所有线程都在这个锁上等待,那么我们可以很轻松地完成测试。我们只需调用 一次countDown()方法就可以让所有的等待线程同时恢复执行。
 - 开始执行前等待n个线程完成各自任务:例如应用程序启动类要确保在处理用户请求前,所有N个外部系统已经启动和运行了。
 - 死锁检测:一个非常方便的使用场景是,你可以使用n个线程访问共享资源,在每次测试阶段的线程数目是不同的,并尝试产生死锁。
 
四 代码实例
描述: 在这个例子中,我们有一个应用调用主类,所有外部系统准备(数据,资源,网络准备等)结束后通知闭锁,主类一致在闭锁等待,直到所有外部准备完成。
抽象类定义: 抽象准备接口(抽象类)
 public abstract class BasePreparer implements Runnable {
     private CountDownLatch countDownLatch;
     private String prepareName;
     private boolean prepareDone;
     public BasePreparer(String prepareName, CountDownLatch countDownLatch) {
         this.countDownLatch = countDownLatch;
         this.prepareName = prepareName;
         this.prepareDone = false;
     }
     protected abstract void prepare();
     @Override
     public void run() {
         try {
             prepare();
             prepareDone = true;
         } catch (Exception e) {
             prepareDone = false;
         } finally {
             if (countDownLatch != null) {
                 countDownLatch.countDown();
             }
         }
     }
     public String getPrepareName() {
         return prepareName;
     }
     public boolean isPrepareDone() {
         return prepareDone;
     }
 }
抽象类
实现类1: 模拟数据准备(后面2,3类似,只是成员变量简单变化)
 public class DataPreparer extends BasePreparer {
     public DataPreparer(CountDownLatch countDownLatch) {
         super("data prepare", countDownLatch);
     }
     @Override
     protected void prepare() {
         System.out.println(this.getPrepareName() + "is doing");
         try {
             TimeUnit.SECONDS.sleep(1);
         } catch (InterruptedException e) {
             e.printStackTrace();
         }
         System.out.println(this.getPrepareName() + "is done");
     }
 }
实现类1
实现类2: 模拟网络准备
 public class NetworkPreparer extends BasePreparer {
     public NetworkPreparer(CountDownLatch countDownLatch) {
         super("network prepare", countDownLatch);
     }
     @Override
     protected void prepare() {
         System.out.println(this.getPrepareName() + "is doing");
         try {
             TimeUnit.SECONDS.sleep(1);
         } catch (InterruptedException e) {
             e.printStackTrace();
         }
         System.out.println(this.getPrepareName() + "is done");
     }
 }
实现类2
实现类3: 模拟资源准备
 public class ResourcePreparer extends BasePreparer {
     public ResourcePreparer(CountDownLatch countDownLatch) {
         super("resource prepare", countDownLatch);
     }
     @Override
     protected void prepare() {
         System.out.println(this.getPrepareName() + "is doing");
         try {
             TimeUnit.SECONDS.sleep(1);
         } catch (InterruptedException e) {
             e.printStackTrace();
         }
         System.out.println(this.getPrepareName() + "is done");
     }
 }
实现类3
主调用类
 public class CountDownLatchMain {
     private static final int LATCH_NUMBER = 3;
     public static void main(String[] args) throws InterruptedException {
         List<BasePreparer> preparerList = Lists.newArrayListWithExpectedSize(LATCH_NUMBER);
         CountDownLatch countDownLatch = new CountDownLatch(LATCH_NUMBER);
         preparerList.add(new ResourcePreparer(countDownLatch));
         preparerList.add(new DataPreparer(countDownLatch));
         preparerList.add(new NetworkPreparer(countDownLatch));
         ExecutorService executorService = Executors.newFixedThreadPool(LATCH_NUMBER);
         preparerList.forEach(executorService::execute);
         countDownLatch.await();
         List<BasePreparer> readyList = preparerList.stream().filter(BasePreparer::isPrepareDone).collect(Collectors.toList());
         System.out.println(readyList.size() == LATCH_NUMBER);
     }
 }
主调用类
运行结果
resource prepareis doing
network prepareis doing
data prepareis doing
network prepareis done
data prepareis done
resource prepareis done
true
运行结果
「java.util.concurrent并发包」之 CountDownLatch的更多相关文章
- 「java.util.concurrent并发包」之 ThreadPoolExecutor
		
一 异步用new Thread? 大写的"low"!! new Thread(new Runnable() { @Override public void run() { // T ...
 - 「java.util.concurrent并发包」之 CopyOnWrite
		
一 CopyOnWrite容器概述 Copy-On-Write简称COW,是一种用于程序设计中的优化策略.其基本思路是,从一开始大家都在共享同一个内容,当某个人想要修改这个内容的时候,才会真正把内容C ...
 - 「java.util.concurrent并发包」之 ReentrantReadWriteLock
		
一 引言 在多线程的环境下,对同一份数据进行读写,会涉及到线程安全的问题.比如在一个线程读取数据的时候,另外一个线程在写数据,而导致前后数据的不一致性:一个线程在写数据的时候,另一个线程也在写,同样也 ...
 - 「java.util.concurrent并发包」之 CAS
		
一 引言 在JDK 5之前Java语言是靠synchronized关键字保证同步的,这会导致有锁 锁机制存在以下问题: (1)在多线程竞争下,加锁.释放锁会导致比较多的上下文切换和调度延时,引起性能 ...
 - 「java.util.concurrent并发包」之 CyclicBarrier
		
一 描述 CyclicBarrier初始化时规定一个数目,然后计算调用了CyclicBarrier.await()进入等待的线程数.当线程数达到了这个数目时,所有进入等待状态的线程被唤醒并继续.Cyc ...
 - Java并发:多线程和java.util.concurrent并发包总结
		
多线程和java.util.concurrent并发包 转载:
 - Java并发—java.util.concurrent并发包概括(转载)
		
一.描述线程的类:Runable和Thread都属于java.lang包 二.内置锁synchronized属于jvm关键字,内置条件队列操作接口Object.wait()/notify()/noti ...
 - java.util.concurrent并发包诸类概览
		
java.util.concurrent包的类都来自于JSR-166:Concurrent Utilities,官方的描述叫做“The JSR proposes a set of medium-lev ...
 - java多线程---------java.util.concurrent并发包----------等待多线程完成
		
一.等待多线程完成的join的使用.CoundownLantch.CyclicBarrier .
 
随机推荐
- I am coming..
			
It's so great to start the blog here since it's been a long time that I want to start such kind of l ...
 - jmeter从文件中读取参数,并实现循环
			
1. 通过BeanShell Sampler获取csv的行数 import java.io.BufferedReader;import java.io.FileReader;BufferedReade ...
 - 利用状态机(FSM)进行简单的uart串口发送数据
			
module uart_tx(clk,rst_n,key,txd); input clk; input rst_n; input key; output reg txd; :] state; :] b ...
 - Pytest学习笔记(二) 用例执行规则
			
在用pytest执行用例时,可以按照如下场景来执行 1.执行目录及其子目录下的所有用例 pytest filename\ 2.执行某一个py文件下的用例 pytest filename.py 3.-k ...
 - Python3 Address already in use 解决方法
			
1.查看使用端口号netstat -ntlp 2.根据端口号找到pid 3.杀死程序 kill -9 pid 4.重新启动程序 简单粗暴 我使用python3时编写Socket,linux系统下使用c ...
 - Leetcode题目200.岛屿数量(BFS+DFS+并查集-中等)
			
题目描述: 给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量.一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的.你可以假设网格的四个边均被水包围. 示例 ...
 - OUC_Summer Training_ DIV2_#7       718
			
是18号做的题啦,现在才把报告补上是以前不重视报告的原因吧,不过现在真的很喜欢写报告,也希望能写一些有意义的东西出来. A - Dragons Time Limit:2000MS Memory ...
 - LeetCode 240. 搜索二维矩阵 II(Search a 2D Matrix II)
			
题目描述 编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target.该矩阵具有以下特性: 每行的元素从左到右升序排列. 每列的元素从上到下升序排列. 示例: 现有矩阵 m ...
 - FreeMarker学习(常用表达式)
			
直接指定值 字符串: "Foo" 或者 'Foo' 或者 "It's \"quoted\"" 或者 'It\'s "quoted& ...
 - article收藏
			
sca https://github.com/spring-cloud-incubator/spring-cloud-alibaba spring-cloud-document https://git ...