CountDownLatch简介

(1)用于解决什么问题?

在并发编程的场景中,最常见的一个case是某个任务的执行,需要等到多个线程都执行完毕之后才可以进行,CountDownLatch可以很好解决这个问题。

(2)使用说明

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

(3)CountDownLatch的常用方法

1.构造方法:

// 构造器,必须指定一个大于零的计数
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
// Sync 就是继承了一个AQS
this.sync = new Sync(count);
}

2.await方法

// 线程阻塞,直到计数为0的时候唤醒;可以响应线程中断退出阻塞
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
// 线程阻塞一段时间,如果计数依然不是0,则返回false;否则返回true
public boolean await(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}

await内部实现流程:

  1. 判断state计数是否为0,不是,则直接放过执行后面的代码;
  2. 大于0,则表示需要阻塞等待计数为0;
  3. 当前线程封装Node对象,进入阻塞队列;
  4. 然后就是循环尝试获取锁,直到成功(即state为0)后出队,继续执行线程后续代码。

await是通过轮询state的状态来判断所有的任务是否都完成。

3.countDown方法

// 计数-1
public void countDown() {
sync.releaseShared(1);
}

countDown内部实现流程:

  1. 尝试释放锁tryReleaseShared,实现计数-1
  • 若计数已经小于0,则直接返回false;
  • 否则执行计数(AQS的state)减一;
  • 若减完之后,state==0,表示没有线程占用锁,即释放成功,然后就需要唤醒被阻塞的线程了;
  1. 释放并唤醒阻塞线程 doReleaseShared;
  • 如果队列为空,即表示没有线程被阻塞(也就是说没有线程调用了 CountDownLatch#wait()方法),直接退出;
  • 头结点如果为SIGNAL, 则依次唤醒头结点下个节点上关联的线程,并出队;

4.getCount方法

// 获取计数
public long getCount() {
return sync.getCount();
}

(4)小例子:计算多个线程并发运行的时间。

public class TestCountDownLatch {

    public static void main(String[] args) throws InterruptedException {
long start = System.currentTimeMillis();
CountDownLatch countDownLatch = new CountDownLatch(5);
CountDownLatchThread countDownLatchThread = new CountDownLatchThread(countDownLatch);
for (int i = 0; i < 5; i++){
new Thread(countDownLatchThread).start();
}
// 主线程等待
countDownLatch.await();
long end = System.currentTimeMillis();
System.out.println("time : " + (end - start));
}
} class CountDownLatchThread implements Runnable{
private CountDownLatch countDownLatch = null;
public CountDownLatchThread(CountDownLatch countDownLatch){
this.countDownLatch = countDownLatch;
}
@Override
public void run() {
synchronized (this){
// 加入try确保countDownLatch.countDown()一定会执行
try {
for (int i = 0; i < 10; i++){
System.out.println(Thread.currentThread().getName() + " : " + i);
}
}finally {
countDownLatch.countDown();
}
}
}
}

参考文献

本片文章,主要整理自互联网,便于自己复习知识所用,以下为参考链接!

【1】Java并发学习之CountDownLatch实现原理及使用姿势

【2】CountDownLatch源码解析

CountDownLatch(三)的更多相关文章

  1. 多线程辅助类之CountDownLatch(三)

    CountDownLatch信号灯是一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待.它可以实现多线程的同步互斥功能,和wait和notify方法实现功能类似,具体 ...

  2. Java Thread系列(四)线程通信

    Java Thread系列(四)线程通信 一.传统通信 public static void main(String[] args) { //volatile实现两个线程间数据可见性 private ...

  3. 多线程辅助类之CyclicBarrier(四)

    CyclicBarrier是一个线程辅助类,和<多线程辅助类之CountDownLatch(三)>功能类似,都可以实现一组线程的相互等待.要说不通点,那就是CyclicBarrier在释放 ...

  4. 并发编程(三):从AQS到CountDownLatch与ReentrantLock

    一.目录      1.AQS简要分析      2.谈CountDownLatch      3.谈ReentrantLock      4.谈消费者与生产者模式(notfiyAll/wait.si ...

  5. Java并发编程_wait/notify和CountDownLatch的比较(三)

     1.wait/notify方法 package sync; import java.util.ArrayList; import java.util.List; public class WaitA ...

  6. 带你看看Java的锁(三)-CountDownLatch和CyclicBarrier

    带你看看Java中的锁CountDownLatch和CyclicBarrier 前言 基本介绍 使用和区别 核心源码分析 总结 前言 Java JUC包中的文章已经写了好几篇了,首先我花了5篇文章从源 ...

  7. 【Java并发核心三】CountDownLatch、CyclicBarrier及Phaser

    个人感觉,看书学习还是需要“不求甚解”,因为一旦太过于计较小的得失,就容易钻牛角尖,学习进度也慢.我们完全可以先学一个大概,等到真正用到的时候再把那些细节丰富起来,就更有针对性. 所以,针对java并 ...

  8. Java并发编程原理与实战三十:CountDownLatch与CyclicBarrier 区别

    相信每个想深入了解多线程开发的Java开发者都会遇到CountDownLatch和CyclicBarrier,大家也在网上看到各种介绍原理,代码的,以及他们区别(应付面试)的,但是很少能讲清楚:他们到 ...

  9. 多线程编程(三)-CountDownLatch的使用

    CountDownLatch的介绍 类CountDownLatch是同步功能得一个辅助类,使用效果就是给定一个计数,当使用CountDownLatch类的线程判断计数不为0时,则呈wait状态,如果是 ...

随机推荐

  1. Spring容器的简单实现(IOC原理)

    引言:容器是什么?什么是容器?Spring容器又是啥东西?我给Spring容器一个对象名字,为啥能给我创建一个对象呢? 一.容器是装东西的,就像你家的水缸,你吃饭的碗等等. java中能作为容器的有很 ...

  2. vue-cli sass安装

    一.安装对应依赖node模块: npm install node-sass --save-dev npm install sass-loader --save-dev 二.打开webpack.base ...

  3. 从零开始搭建django前后端分离项目 系列六(实战之聚类分析)

    项目需求 本项目从impala获取到的数据为用户地理位置数据,每小时的数据量大概在8000万条,数据格式如下: 公司要求对这些用户按照聚集程度进行划分,将300米范围内用户数大于200的用户划分为一个 ...

  4. Python3 tkinter基础 Checkbutton variable 多选钮是否被选中

             Python : 3.7.0          OS : Ubuntu 18.04.1 LTS         IDE : PyCharm 2018.2.4       Conda ...

  5. 【thinkPHP框架】Failed opening required 'header.php' include_path='.;c:\php5\pear 终级解决方案

    ThinkPHP框架中的某一个php页面,想要去引入其他php页面,结果反复报错,无解. 各种百度,有说是文件权限不够的,也有说配置不对的,反正一个都没有解决这个问题,依然无解. 最终,找到了办法,似 ...

  6. ReactJs移动端兼容问题汇总

    汽车H5使用ReactJs问题汇总 Q:安卓4.4webview显示空白? A:初步怀疑是css属性没有加前缀引发的兼容问题,但添加后发现也不行,通过webview调试后控制台输出Set is und ...

  7. Linux iostat 命令

    iostat 命令是 I/O statistics(输入/输出统计)的缩写,用来报告系统的 CPU 统计信息和块设备及其分区的 IO 统计信息.iostat 是 sysstat 工具集的一个工具,在 ...

  8. python中各个response使用

    Python django中我们经常用的response有django中的 JsonResponse, HttpResponse,还有DRF中的Response 在使用的时候,经常会不知道如何什么时候 ...

  9. 第十二次oo作业

    作业十二 规格化设计简介 规格化设计的发展历史 1950年代,第一次分离,主程序与子程序的分离结构是树状模型,子程序可先于主程序编写.通过使用库函数来简化编程,实现最初的代码重用.产生基本的软件开发过 ...

  10. Divide by three, multiply by two CodeForces - 977D (思维排序)

    Polycarp likes to play with numbers. He takes some integer number xx, writes it down on the board, a ...