Java并发编程-CountDownLatch
基于AQS的前世今生,来学习并发工具类CountDownLatch。本文将从CountDownLatch的应用场景、源码原理解析来学习这个并发工具类。
1、 应用场景
CountDownLatch是并发包中用来控制一个或者多个线程等待其他线程完成操作的并发工具类。现以工作中的一个场景来描述下CountDownLatch的应用,代码如下:
/*
模拟工作中的一个需求场景:
用户会选择多个算法来计算费用,最后会将所有算法计算出的费用做一个加权求平均数,这个平均数是最终的费用。
每个算法的复杂度都不一样,打算每个线程负责一个算法的实现,所有的线程执行完成,最后再求平均数。
1、为每个算法创建一个线程,每个线程负责一个算法的实现
2、通过CountDownLatch来控制所有算法线程的同步
3、全部计算完成后再求平均数
*/
public class CountDownLatchTask { public static void main(String[] args) {
CountDownLatchTask countDownLatchTask = new CountDownLatchTask();
countDownLatchTask.startThreads(5);
}
//根据线程数和选择的算法 调度算法对应的实现
private void startThreads(int threadNumber) {
CountDownLatch countDownLatch = new CountDownLatch(threadNumber);
for (int i = 0; i < threadNumber; i++) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程算法实现:" + Thread.currentThread().getName());
countDownLatch.countDown();
}
}).start();
}
try {
countDownLatch.await();
System.out.println("加权求平均数");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
在分析原理实现前,总结下CountDownLatch的作用就是阻塞其他线程直到条件允许后才释放该阻塞,除了上述这个小案例,实际工作中还有很多可以使用CountDownLatch的场景,比如解析Excel文件时可以同时解析多个Sheet页,所有的Sheet解析完成才算完成了Excel文件的解析。从这个代码中也可以看到CountDownLatch的主要方法就是await和countDown,下面将以这两个方法来分析下CountDownLatch的原理实现。
2、 源码原理解析
2.1 await方法
调用await方法会阻塞当前线程直到计数器的数值为0,方法如下:
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1); //共享式获取AQS的同步状态
}
调用的是AQS的acquireSharedInterruptibly方法:
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())//线程中断 说明闭锁对线程中断敏感
throw new InterruptedException();
if (tryAcquireShared(arg) < 0) //闭锁未使用完成 线程进入同步队列自旋等待
doAcquireSharedInterruptibly(arg);
}
其中tryAcquireShared依赖的是Sync的实现,和之前的ReentrantLock、ReentrantReadWriteLock及Semaphore相比,CountDownLatch的Sync只提供了一种方式,代码如下:
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1; //AQS的同步状态为0则闭锁结束 可以进行下一步操作
}
doAcquireSharedInterruptibly方法就不再赘述,和之前Semaphore的实现是一致的,本质上仍然是AQS同步队列的入队自旋等待。
2.2 countDown方法
调用countDown方法会将计数器的数值减1直到计数器为0,方法如下:
public void countDown() {
sync.releaseShared(1);
}
和Semaphore一样,调用的是AQS的releaseShared方法:
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {//减少闭锁的计数器
doReleaseShared();//唤醒后续线程节点
return true;
}
return false;
}
其中tryReleaseShared依赖的是Sync的实现,和之前的ReentrantLock、ReentrantReadWriteLock及Semaphore相比,CountDownLatch的Sync只提供了一种方式,代码如下:
protected boolean tryReleaseShared(int releases) {
// Decrement count; signal when transition to zero
for (;;) {
int c = getState();
if (c == 0)
return false; //计数器已经是0了
int nextc = c-1; //计数器减1
if (compareAndSetState(c, nextc)) //CAS更新同步状态
return nextc == 0;
}
}
唤醒后续线程节点的doReleaseShared也不再赘述,和之前Semaphore的实现是一致的。
总结:CountDownLatch类使用AQS同步状态来表示计数。在await时,所有的线程进入同步队列自旋等待,在countDown时,获取闭锁成功的线程会减少闭锁的计数器,同时唤醒后续线程取获取闭锁,直到await中的计数器为0,获取到闭锁的线程才可以通过,执行下一步操作。
参考资料:
https://github.com/lingjiango/ConcurrentProgramPractice
Java并发编程-CountDownLatch的更多相关文章
- java并发编程CountDownLatch
/** * CountDownLatch用法 * CountDownLatch类位于java.util.concurrent包下,利用它可以实现类似计数器的功能.比如有一个任务A, * 它要等待其他4 ...
- 【Java并发编程实战】-----“J.U.C”:CountDownlatch
上篇博文([Java并发编程实战]-----"J.U.C":CyclicBarrier)LZ介绍了CyclicBarrier.CyclicBarrier所描述的是"允许一 ...
- Java并发编程:CountDownLatch、CyclicBarrier和Semaphore
Java并发编程:CountDownLatch.CyclicBarrier和Semaphore 在java 1.5中,提供了一些非常有用的辅助类来帮助我们进行并发编程,比如CountDownLatch ...
- Java并发编程的4个同步辅助类(CountDownLatch、CyclicBarrier、Semaphore、Phaser)
我在<JDK1.5引入的concurrent包>中,曾经介绍过CountDownLatch.CyclicBarrier两个类,还给出了CountDownLatch的演示案例.这里再系统总结 ...
- Java并发编程的4个同步辅助类(CountDownLatch、CyclicBarrier、Semphore、Phaser)
我在<jdk1.5引入的concurrent包>中,曾经介绍过CountDownLatch.CyclicBarrier两个类,还给出了CountDownLatch的演示案例.这里再系统总结 ...
- Java并发编程:CountDownLatch、CyclicBarrier和Semaphore (总结)
下面对上面说的三个辅助类进行一个总结: 1)CountDownLatch和CyclicBarrier都能够实现线程之间的等待,只不过它们侧重点不同: CountDownLatch一般用于某个线程A等待 ...
- 14、Java并发编程:CountDownLatch、CyclicBarrier和Semaphore
Java并发编程:CountDownLatch.CyclicBarrier和Semaphore 在java 1.5中,提供了一些非常有用的辅助类来帮助我们进行并发编程,比如CountDownLatch ...
- 【转】Java并发编程:CountDownLatch、CyclicBarrier和Semaphore
Java并发编程:CountDownLatch.CyclicBarrier和Semaphore Java并发编程:CountDownLatch.CyclicBarrier和Semaphore 在j ...
- java并发编程JUC第九篇:CountDownLatch线程同步
在之前的文章中已经为大家介绍了java并发编程的工具:BlockingQueue接口.ArrayBlockingQueue.DelayQueue.LinkedBlockingQueue.Priorit ...
随机推荐
- ASP.NET MVC项目中App_Code目录在程序应用
学习ASP.NET MVC,如果你是开发ASP.NET MVC项目的,也许你去为项目添加前ASP.NET项目的APP_Code目录,在这里创建与添加的Class类,也许你无法在MVC项目所引用. 那这 ...
- Java基础巩固——异常
基础回顾 什么是异常? 在Java程序运行时,常常会出现一些非正常的现象,这种情况称为运行错误.根据其性质可以分为错误和异常. Java程序中所有抛出的异常都必须从Throwable派生而来.类Thr ...
- 目标检测算法(1)目标检测中的问题描述和R-CNN算法
目标检测(object detection)是计算机视觉中非常具有挑战性的一项工作,一方面它是其他很多后续视觉任务的基础,另一方面目标检测不仅需要预测区域,还要进行分类,因此问题更加复杂.最近的5年使 ...
- 基于APNs最新HTTP/2接口实现iOS的高性能消息推送(服务端篇)
1.前言 本文要分享的消息推送指的是当iOS端APP被关闭或者处于后台时,还能收到消息/信息/指令的能力. 这种在APP处于后台或关闭情况下的消息推送能力,通常在以下场景下非常有用: 1)IM即时通讯 ...
- C/C++ 多线程机制
一.C/C++多线程操作说明 C/C++多线程基本操作如下: 1. 线程的建立结束 2. 线程的互斥和同步 3. 使用信号量控制线程 4. 线程的基本属性配置 在C/C++代码编写时,使用多线程机制, ...
- Javascript高级编程学习笔记(54)—— DOM2和DOM3(6)范围选择
范围 为了让开发人员更加方便地控制页面“DOM2级遍历和范围”模块定义了“范围”接口 通过该接口开发人员可以选择文档中的一个区域,而不必考虑元素的界限 在常规操作不能有效地修改文档时,使用范围往往可以 ...
- 每天学点SpringCloud(十二):Zipkin全链路监控
Zipkin是SpringCloud官方推荐的一款分布式链路监控的组件,使用它我们可以得知每一个请求所经过的节点以及耗时等信息,并且它对代码无任何侵入,我们先来看一下Zipkin给我们提供的UI界面都 ...
- Python 函数中参数的分类及使用
######################非固定参数################## #第一种方式:def send_alert(msg,*users):##*users 是非固定参数,将传过来 ...
- Python爬虫-萌妹子图片
最近发现一个可以看图的地方,一张张翻有点累,毕竟只有一只手(难道鼠标还能两只手翻?).能不能下到电脑上看呢,毕竟不用等网速,还可以预览多张,总之很方便,想怎么就怎么,是吧? 刚好这几天在学python ...
- 消除浏览器对input的自动填充
在做登录相关的页面时,常遇到这样的现象,浏览器input的自动填充行为. 原因 设置 input 的 type 属性为 password 后,当页面进行过提交,并且允许浏览器记住密码后,那么再次加载该 ...