Java并发编程之CountDownLatch
一、场景描述
在多线程程序设计中,经常会遇到一个线程等待一个或多个线程的场景
例如:百米赛跑,十名运动员同时起跑,由于速度的快慢,肯定有先到达和后到达的,而终点有个统计成绩的仪器,当所有选手到达终点时,它会统计所有人的成绩并进行排序,然后把结果发送到汇报成绩的系统。
再例如:当我们需要解析一个Excel里多个sheet的数据时,可以考虑使用多线程,每个线程解析一个sheet里的数据,等到所有的sheet都解析完之后,程序需要提示解析完成。在这个需求中,要实现主线程等待所有线程完成sheet的解析操作。
以上场景是一个线程等待多个线程,则就可以使用CountDownLatch来实现比较好的控制
二、CountDownLatch如何工作的
正如Java文档所描述的那样,CountDownLatch是一个同步工具类,它允许一个或多个线程一直等待,直到其他线程的操作执行完后再执行。CountDownLatch是在Java1.5被引入的,跟它一起被引入的并发工具类还有CyclicBarrier、Semaphore、ConcurrentHashMap和BlockingQueue,它们都存在于java.util.concurrent包下。
CountDownLatch是通过一个计数器来实现的,计数器的初始值为线程的数量。每当一个线程完成了自己的任务后,计数器的值就会减1。当计数器值到达0时,它表示所有的线程已经完成了任务,然后在闭锁上等待的线程就可以恢复执行任务。
三、方法说明
public void CountDownLatch(int count) {…}
构造器中的计数值(count)实际上就是闭锁需要等待的线程数量。这个值只能被设置一次,而且CountDownLatch**没有提供任何机制去重新设置这个计数值**。
public void countDown()
其他线程必须引用闭锁对象,因为他们需要通知CountDownLatch对象,他们已经完成了各自的任务。这种通知机制是通过CountDownLatch.countDown()方法来完成的,每调用一次这个方法,在构造函数中初始化的count值就减1.所以当N个线程都调用了这个方法,count的值等于0,然后主线程就能通过await()方法,恢复执行自己的任务。
public void await()
当线程调用了 await(),则这个线程就等待这个计数器变为0,当这个计数器变为0时,这个线程继续自己下面的工作。
代码示例:
package com.itmyhome;
import java.util.concurrent.CountDownLatch;
/**
* 运动员
* @author itmyhome
*
*/
class Athlete implements Runnable {
private String name; // 姓名
private CountDownLatch beginSignal;
private CountDownLatch endSignal;
public Athlete(String name, CountDownLatch begin, CountDownLatch end) {
this.name = name;
this.beginSignal = begin;
this.endSignal = end;
}
@Override
public void run() {
try {
beginSignal.await();
System.out.println("运动员:" + name + " 到达终点...");
endSignal.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 终点统计类
* @author itmyhome
*
*/
public class CountDownLatchTest {
public static void main(String[] args) {
CountDownLatch begSignal = new CountDownLatch(1);
CountDownLatch endSignal = new CountDownLatch(10);
for (int i = 0; i < 10; i++) {
new Thread(new Athlete("name" + i, begSignal, endSignal)).start();
}
try {
begSignal.countDown(); // 统一起跑
endSignal.await(); // 等待运动员到达终点
// Thread.sleep(1);
System.out.println("结果发送到汇报成绩的系统");
} catch (Exception e) {
e.printStackTrace();
}
}
}
输出结果:
运动员:name0 到达终点...
运动员:name4 到达终点...
运动员:name9 到达终点...
运动员:name5 到达终点...
运动员:name3 到达终点...
运动员:name6 到达终点...
运动员:name1 到达终点...
运动员:name7 到达终点...
运动员:name8 到达终点...
运动员:name2 到达终点...
结果发送到汇报成绩的系统
Java并发编程之CountDownLatch的更多相关文章
- Java并发编程之CountDownLatch,CyclicBarrier实现一组线程相互等待、唤醒
java多线程应用场景不少,有时自己编写代码又不太容易实现,好在concurrent包提供了不少实现类,还有google的guava包更是提供了一些最佳实践,这让我们在面对一些多线程的场景时,有了不少 ...
- Java并发编程之CountDownLatch的用法
一.含义 CountDownLatch类位于java.util.concurrent包下,利用它可以实现类似计数器的功能.CountDownLatch是一个同步的辅助类,它可以允许一个或多个线程等待, ...
- Java并发编程之CAS
CAS(Compare and swap)比较和替换是设计并发算法时用到的一种技术.简单来说,比较和替换是使用一个期望值和一个变量的当前值进行比较,如果当前变量的值与我们期望的值相等,就使用一个新值替 ...
- Java并发编程之CAS第一篇-什么是CAS
Java并发编程之CAS第一篇-什么是CAS 通过前面几篇的学习,我们对并发编程两个高频知识点了解了其中的一个—volatitl.从这一篇文章开始,我们将要学习另一个知识点—CAS.本篇是<凯哥 ...
- Java并发编程之CAS二源码追根溯源
Java并发编程之CAS二源码追根溯源 在上一篇文章中,我们知道了什么是CAS以及CAS的执行流程,在本篇文章中,我们将跟着源码一步一步的查看CAS最底层实现原理. 本篇是<凯哥(凯哥Java: ...
- Java并发编程之CAS第三篇-CAS的缺点及解决办法
Java并发编程之CAS第三篇-CAS的缺点 通过前两篇的文章介绍,我们知道了CAS是什么以及查看源码了解CAS原理.那么在多线程并发环境中,的缺点是什么呢?这篇文章我们就来讨论讨论 本篇是<凯 ...
- Java并发编程之set集合的线程安全类你知道吗
Java并发编程之-set集合的线程安全类 Java中set集合怎么保证线程安全,这种方式你知道吗? 在Java中set集合是 本篇是<凯哥(凯哥Java:kagejava)并发编程学习> ...
- Java并发编程之AQS
一.什么是AQS AQS(AbstractQueuedSynchronize:队列同步器)是用来构建锁或者其他同步组件的基础框架,很多同步类都是在它的基础上实现的,比如常用的ReentrantLock ...
- Java并发编程之Lock
重入锁ReentrantLock 可以代替synchronized, 但synchronized更灵活. 但是, 必须必须必须要手动释放锁. try { lock.lock(); } finally ...
随机推荐
- Numpy中的时间类型
从Numpy1.7开始,已经有了原生的日期-时间支持,基本类型称为datetime64. In [1]: import numpy as np In [2]: nd = np.datetime64(' ...
- adas--智能驾驶辅助系统
先进驾驶辅助系统(Advanced Driver AssistantSystem),简称ADAS,是利用安装于车上的各式各样的传感器(可侦测光.热.压力等变数), 在第一时间收集车内外的环境数据, 进 ...
- Oracle大总结
maven的常见两个指令说明 mvn install 是将你打好的jar包安装到你的本地库中,一般没有设置过是在 用户目录下的 .m2\下面.mvn package 只是将你的代码打包到输出目录,一般 ...
- 华为交换机S5700系列配置镜像端口(M:N)
配置本地端口镜像组网图(M:N) 组网需求 如图所示,某公司研发一部.研发二部和市场部通过Switch与外部Internet通信,监控设备Server1.Server2与Switch直连. 现在希望将 ...
- MongoDB快速入门(十二) -- 索引
MongoDB 索引 索引支持的解析度的查询效率.如果没有索引,MongoDB必须扫描每一个文档的集合,要选择那些文档相匹配的查询语句.这种扫描的效率非常低,会要求 mongod 做大数据量的处理. ...
- cf780c
C. Andryush ...
- Docker高级使用
Docker卸载应用程序 先删除容器,在删除镜像 查询容器 docker ps –a 使用容器id删除容器 docker rm 18e672ecd8ed 查询镜像 docker images 使用镜像 ...
- [CTSC2008]祭祀river
Description 在遥远的东方,有一个神秘的民族,自称Y族.他们世代居住在水面上,奉龙王为神.每逢重大庆典, Y族都 会在水面上举办盛大的祭祀活动.我们可以把Y族居住地水系看成一个由岔口和河道组 ...
- springBean获取的几种方法
1.通过FileSystemApplicationContext来获取(不常用,因为要spring配置文件的绝对路径) 2.通过ClassPathXmlApplicationContext来获取(常用 ...
- java 多继承的典型应用实例(不同的报文不同的方法去解析)
关于 java 多继承的典型应用实例 针对不同业务类型的XML文件的解析 在PCS 项目: public class CainiaoXMLMessageResolverServiceImpl impl ...