java 并发工具类CountDownLatch & CyclicBarrier
一起在java1.5被引入的并发工具类还有CountDownLatch、CyclicBarrier、Semaphore、ConcurrentHashMap和BlockingQueue,它们都存在于java.util.concurrent包下。
CountDownLatch
CountDownLatch 概念
CountDownLatch这个类能够使一个线程等待其他线程完成各自的工作后再执行。例如,应用程序的主线程希望在负责启动框架服务的线程已经启动所有的框架服务之后再执行。
CountDownLatch是通过一个计数器来实现的,计数器的初始值为线程的数量。每当一个线程完成了自己的任务后,计数器的值就会减1。当计数器值到达0时,它表示所有的线程已经完成了任务,然后在闭锁上等待的线程就可以恢复执行任务。
图示:
伪代码:
//Main thread start
//Create CountDownLatch for N threads
//Create and start N threads
//Main thread wait on latch
//N threads completes there tasks are returns
//Main thread resume execution
CountDownLatch 如何工作
CountDownLatch.java类中定义的构造函数:
//Constructs a CountDownLatch initialized with the given count.
public void CountDownLatch(int count) {...}
构造器中的计数值(count)实际上就是闭锁需要等待的线程数量。这个值只能被设置一次,而且CountDownLatch没有提供任何机制去重新设置这个计数值。
与CountDownLatch的第一次交互是主线程等待其他线程。主线程必须在启动其他线程后立即调用CountDownLatch.await()方法。这样主线程的操作就会在这个方法上阻塞,直到其他线程完成各自的任务。
其他N 个线程必须引用闭锁对象,因为他们需要通知CountDownLatch对象,他们已经完成了各自的任务。这种通知机制是通过 CountDownLatch.countDown()方法来完成的;每调用一次这个方法,在构造函数中初始化的count值就减1。所以当N个线程都调 用了这个方法,count的值等于0,然后主线程就能通过await()方法,恢复执行自己的任务。
使用场景
我们尝试罗列出在java实时系统中CountDownLatch都有哪些使用场景。我所罗列的都是我所能想到的。如果你有别的可能的使用方法,请在留言里列出来,这样会帮助到大家。
- 实现最大的并行性:有时我们想同时启动多个线程,实现最大程度的并行性。例如,我们想测试一个单例类。如果我们创建一个初始计数为1的CountDownLatch,并让所有线程都在这个锁上等待,那么我们可以很轻松地完成测试。我们只需调用 一次countDown()方法就可以让所有的等待线程同时恢复执行。
- 开始执行前等待n个线程完成各自任务:例如应用程序启动类要确保在处理用户请求前,所有N个外部系统已经启动和运行了。
- 死锁检测:一个非常方便的使用场景是,你可以使用n个线程访问共享资源,在每次测试阶段的线程数目是不同的,并尝试产生死锁。
CountDownLatch使用实例
在这个例子中,我模拟了一个应用程序启动类,它开始时启动了n个线程类,这些线程将检查外部系统并通知闭锁,并且启动类一直在闭锁上等待着。一旦验证和检查了所有外部服务,那么启动类恢复执行。
BaseHealthChecker.java:这个类是一个Runnable,负责所有特定的外部服务健康的检测。它删除了重复的代码和闭锁的中心控制代码。
public abstract class BaseHealthChecker implements Runnable {
private CountDownLatch _latch;
private String _serviceName;
private boolean _serviceUp;
//Get latch object in constructor so that after completing the task, thread can countDown() the latch
public BaseHealthChecker(String serviceName, CountDownLatch latch)
{
super();
this._latch = latch;
this._serviceName = serviceName;
this._serviceUp = false;
}
@Override
public void run() {
try {
verifyService();
_serviceUp = true;
} catch (Throwable t) {
t.printStackTrace(System.err);
_serviceUp = false;
} finally {
if(_latch != null) {
_latch.countDown();
}
}
}
public String getServiceName() {
return _serviceName;
}
public boolean isServiceUp() {
return _serviceUp;
}
//This methos needs to be implemented by all specific service checker
public abstract void verifyService();
}
NetworkHealthChecker.java:这个类继承了BaseHealthChecker,实现了verifyService()方法。DatabaseHealthChecker.java和CacheHealthChecker.java除了服务名和休眠时间外,与NetworkHealthChecker.java是一样的。
public class NetworkHealthChecker extends BaseHealthChecker
{
public NetworkHealthChecker (CountDownLatch latch) {
super("Network Service", latch);
}
@Override
public void verifyService()
{
System.out.println("Checking " + this.getServiceName());
try
{
Thread.sleep(7000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
System.out.println(this.getServiceName() + " is UP");
}
}
ApplicationStartupUtil.java:这个类是一个主启动类,它负责初始化闭锁,然后等待,直到所有服务都被检测完。
public class ApplicationStartupUtil
{
//List of service checkers
private static List<BaseHealthChecker> _services;
//This latch will be used to wait on
private static CountDownLatch _latch;
private ApplicationStartupUtil()
{
}
private final static ApplicationStartupUtil INSTANCE = new ApplicationStartupUtil();
public static ApplicationStartupUtil getInstance()
{
return INSTANCE;
}
public static boolean checkExternalServices() throws Exception
{
//Initialize the latch with number of service checkers
_latch = new CountDownLatch(3);
//All add checker in lists
_services = new ArrayList<BaseHealthChecker>();
_services.add(new NetworkHealthChecker(_latch));
_services.add(new CacheHealthChecker(_latch));
_services.add(new DatabaseHealthChecker(_latch));
//Start service checkers using executor framework
Executor executor = Executors.newFixedThreadPool(_services.size());
for(final BaseHealthChecker v : _services)
{
executor.execute(v);
}
//Now wait till all services are checked
_latch.await();
//Services are file and now proceed startup
for(final BaseHealthChecker v : _services)
{
if( ! v.isServiceUp())
{
return false;
}
}
return true;
}
}
现在你可以写测试代码去检测一下闭锁的功能了。
public class Main {
public static void main(String[] args)
{
boolean result = false;
try {
result = ApplicationStartupUtil.checkExternalServices();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("External services validation completed !! Result was :: "+ result);
}
}
输出如下:
//Output in console:
Checking Network Service
Checking Cache Service
Checking Database Service
Database Service is UP
Cache Service is UP
Network Service is UP
External services validation completed !! Result was :: true
CyclicBarrier
CyclicBarrier 概念
主要的方法就是一个:await()。
await() 方法每被调用一次,计数便会减少1,并阻塞住当前线程。当计数减至0时,阻塞解除,所有在此 CyclicBarrier 上面阻塞的线程开始运行。在这之后,如果再次调用 await() 方法,计数就又会变成 N-1,新一轮重新开始,这便是 Cyclic 的含义所在。
在所有参与者都已经在此 barrier 上调用 await方法之前,将一直等待。如果当前线程不是将到达的最后一个线程,出于调度目的,将禁用它,且在发生以下情况之一前,该线程将一直处于休眠状态:
- 最后一个线程到达;或者
- 其他某个线程中断当前线程;或者
- 其他某个线程中断另一个等待线程;或者
- 其他某个线程在等待 barrier 时超时;或者
- 其他某个线程在此 barrier 上调用 reset()。
- 如果当前线程,在进入此方法时已经设置了该线程的中断状态;或者
- 如果当前线程,在等待时被中断
CyclicBarrier 的使用并不难,但需要注意它所相关的异常。除了常见的异常,CyclicBarrier.await() 方法会抛出一个独有的 BrokenBarrierException。这个异常发生在当某个线程在等待本 CyclicBarrier 时被中断或超时或被重置时,其它同样在这个 CyclicBarrier 上等待的线程便会受到 BrokenBarrierException。意思就是说,同志们,别等了,有个小伙伴已经挂了,咱们如果继续等有可能会一直等下去,所有各回各家吧。
CyclicBarrier.await() 方法带有返回值,用来表示当前线程是第几个到达这个 Barrier 的线程。
和 CountDownLatch 一样,CyclicBarrier 同样可以可以在构造函数中设定总计数值。与 CountDownLatch 不同的是,CyclicBarrier 的构造函数还可以接受一个 Runnable,会在 CyclicBarrier 被释放时执行。
CyclicBarrier 实例
/**
* Description: 赛跑时,等待所有人都准备好时,才起跑:
*
* @author shenlongguang
* @date: 2017/4/27 下午1:50.
*/
public class CyclicBarrierTest {
public static void main(String[] args) throws IOException, InterruptedException {
//如果将参数改为4,但是下面只加入了3个选手,这永远等待下去
//Waits until all parties have invoked await on this barrier.
CyclicBarrier barrier = new CyclicBarrier(5);
ExecutorService executor = Executors.newFixedThreadPool(5);
executor.submit(new Thread(new Runner(barrier, " No.1")));
executor.submit(new Thread(new Runner(barrier, " No.2")));
executor.submit(new Thread(new Runner(barrier, " No.3")));
executor.submit(new Thread(new Runner(barrier, " No.4")));
executor.submit(new Thread(new Runner(barrier, " No.5")));
executor.shutdown();
}
}
class Runner implements Runnable {
// 一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)
private CyclicBarrier barrier;
private String name;
public Runner(CyclicBarrier barrier, String name) {
super();
this.barrier = barrier;
this.name = name;
}
@Override
public void run() {
try {
Thread.sleep(1000 * (new Random()).nextInt(8));
System.out.println(System.currentTimeMillis()+ name + " ready...");
// barrier的await方法,在所有参与者都已经在此 barrier 上调用 await 方法之前,将一直等待。
barrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println(System.currentTimeMillis()+ name + " go!");
}
}
console 输出:
1493272909108 No.5 ready...
1493272910101 No.2 ready...
1493272914101 No.1 ready...
1493272915106 No.3 ready...
1493272915106 No.4 ready...
1493272915106 No.4 go!
1493272915107 No.5 go!
1493272915107 No.3 go!
1493272915107 No.1 go!
1493272915107 No.2 go!
CyclicBarrier 和 CountDownLatch 用法上的不同
CountDownLatch 适用于一组线程和另一个主线程之间的工作协作。一个主线程等待一组工作线程的任务完毕才继续它的执行是使用 CountDownLatch 的主要场景;
CyclicBarrier 用于一组或几组线程,比如一组线程需要在一个时间点上达成一致,例如同时开始一个工作。另外,CyclicBarrier 的循环特性和构造函数所接受的 Runnable 参数也是 CountDownLatch 所不具备的
参考 / 转载:
CountDownLatch英文原文when-to-use-countdownlatch-java-concurrency
CountDownLatch翻译文什么时候使用CountDownLatch
cyclicbarrier示例the-introduction-and-use-of-cyclicbarrier
java 并发工具类CountDownLatch & CyclicBarrier的更多相关文章
- Java并发工具类 - CountDownLatch
Java并发工具类 - CountDownLatch 1.简介 CountDownLatch是Java1.5之后引入的Java并发工具类,放在java.util.concurrent包下面 http: ...
- Java并发工具类CountDownLatch源码中的例子
Java并发工具类CountDownLatch源码中的例子 实例一 原文描述 /** * <p><b>Sample usage:</b> Here is a pai ...
- Java中的4个并发工具类 CountDownLatch CyclicBarrier Semaphore Exchanger
在 java.util.concurrent 包中提供了 4 个有用的并发工具类 CountDownLatch 允许一个或多个线程等待其他线程完成操作,课题点 Thread 类的 join() 方法 ...
- 25.大白话说java并发工具类-CountDownLatch,CyclicBarrier,Semaphore,Exchanger
1. 倒计时器CountDownLatch 在多线程协作完成业务功能时,有时候需要等待其他多个线程完成任务之后,主线程才能继续往下执行业务功能,在这种的业务场景下,通常可以使用Thread类的join ...
- JAVA并发工具类---------------(CountDownLatch和CyclicBarrier)
CountDownLatch是什么 CountDownLatch,英文翻译为倒计时锁存器,是一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待. 闭锁可以延迟线程的进 ...
- Java 并发工具类 CountDownLatch、CyclicBarrier、Semaphore、Exchanger
本文部分摘自<Java 并发编程的艺术> CountDownLatch CountDownLatch 允许一个或多个线程等待其他线程完成操作.假设现有一个需求:我们需要解析一个 Excel ...
- Java并发编程工具类 CountDownLatch CyclicBarrier Semaphore使用Demo
Java并发编程工具类 CountDownLatch CyclicBarrier Semaphore使用Demo CountDownLatch countDownLatch这个类使一个线程等待其他线程 ...
- 30行自己写并发工具类(Semaphore, CyclicBarrier, CountDownLatch)是什么体验?
30行自己写并发工具类(Semaphore, CyclicBarrier, CountDownLatch)是什么体验? 前言 在本篇文章当中首先给大家介绍三个工具Semaphore, CyclicBa ...
- 基于AQS实现的Java并发工具类
本文主要介绍一下基于AQS实现的Java并发工具类的作用,然后简单谈一下该工具类的实现原理.其实都是AQS的相关知识,只不过在AQS上包装了一下而已.本文也是基于您在有AQS的相关知识基础上,进行讲解 ...
随机推荐
- 2102: [Usaco2010 Dec]The Trough Game
2102: [Usaco2010 Dec]The Trough Game Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 117 Solved: 84[ ...
- 关于wxpython多线程研究包括(import Publisher错误研究)
作为一个自动化测试人员,开发基本的应用桌面程序是必须的!最近在研究wxpython相关知识,目前看到多线程一块,发现官方文档介绍说:"在线程中不能修改修改窗口属性!",但是实际情况 ...
- elastic search 学习 一
初步阅读了elastic search 的文档,并使用command实践操作. 大概明白其概念模型.
- QT Creator 快速入门教程 读书笔记(一)
一 Qt简介 Qt 是一个跨平台的C++应用程序框架,支持Windows.Linux.Mac OS X.Android.iOS.Windows Phone.嵌入式系统等.也就是说,Qt 可以同时支持桌 ...
- GitHub中最强大的iOS Notifications和AlertView框架,没有之一!
FFToast是一个非常强大的iOS message notifications和AlertView扩展.它可以很容易实现从屏幕顶部.屏幕底部和屏幕中间弹出一个通知.你可以很容易的自定义弹出的View ...
- linux ip 转发设置 ip_forward
工作原理: 内网主机向公网发送数据包时,由于目的主机跟源主机不在同一网段,所以数据包暂时发往内网默认网关处理,而本网段的主机对此数据包不做任何回应.由于源主机ip是私有的,禁止在公网使用,所以必须将数 ...
- linux shell 找端口号及对应的进程
#!/bin/bash#author:zhongyulin#crteate-time:2016-10-20 netstat -lnpt|grep -v grep>/tmp/script/nets ...
- css3-逐帧动画
time,这里有两个时间,前面一个是规定完成这个动画所需要的时间,全称叫animation-duration,第二个time为动画延迟开始播放的时间,全称叫animation-delay,这两个数值可 ...
- iOS 10 语音识别Speech Framework详解
最近做了一个项目,涉及到语音识别,使用的是iOS的speech Framework框架,在网上搜了很多资料,也看了很多博客,但介绍的不是很详细,正好项目做完,在这里给大家详解一下speech Fram ...
- ATL dll注册失败
“生成”->“生成解决方案”或“重新生成解决方案”,在注册时,报错:regisvr32 /r/c " C:\Users\Administrator\Desktop\复件DrvWater ...