1.背景:

  • countDownLatch是在java1.5被引入,跟它一起被引入的工具类还有CyclicBarrier、Semaphore、concurrentHashMap和BlockingQueue。
  • 存在于java.util.cucurrent包下。

2.概念

  • countDownLatch这个类使一个线程等待其他线程各自执行完毕后再执行。
  • 是通过一个计数器来实现的,计数器的初始值是线程的数量。每当一个线程执行完毕后,计数器的值就-1,当计数器的值为0时,表示所有线程都执行完毕,然后在闭锁上等待的线程就可以恢复工作了。

3.使用场景

example1

为了能够理解CountDownLatch,举一个很通俗的例子,运动员进行跑步比赛时,假设有6个运动员参与比赛,裁判员在终点会为这6个运动员分别计时,
可以想象每当一个运动员到达终点的时候,对于裁判员来说就少了一个计时任务。直到所有运动员都到达终点了,裁判员的任务也才完成。这6个运动员可
以类比成6个线程,当线程调用CountDownLatch.countDown方法时就会对计数器的值减一,直到计数器的值为0的时候,裁判员(调用await方法的线程)
才能继续往下执行。

下面来看些CountDownLatch的一些重要方法。
先从CountDownLatch的构造方法看起:

public CountDownLatch(int count)

构造方法会传入一个整型数N,之后调用CountDownLatch的 countDown 方法会对N减一,知道N减到0的时候,当前调用 await 方法的线程继续执行。
CountDownLatch的方法不是很多,将它们一个个列举出来:
1. await() throws InterruptedException:调用该方法的线程等到构造方法传入的N减到0的时候,才能继续往下执行;
2. await(long timeout, TimeUnit unit):与上面的await方法功能一致,只不过这里有了时间限制,调用该方法的线程等到指定的timeout时间后,不管N是
否减至为0,都会继续往下执行;
3. countDown():使CountDownLatch初始值N减1;
4. long getCount():获取当前CountDownLatch维护的值;

下面用一个具体的例子来说明CountDownLatch的具体用法:

package com.example.demo.test;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; /**
*
* @version V1.0 15:44 guozl
* @since 1.0
*/
public class CountDownLatchDemo {
private static CountDownLatch startSignal = new CountDownLatch(1);
//用来表示裁判员需要维护的是6个运动员
private static CountDownLatch endSignal = new CountDownLatch(6);
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(6);
for (int i = 0; i < 6; i++) {
executorService.execute(() -> {
try {
System.out.println(Thread.currentThread().getName() + " 运动员就位等待裁判员响哨!!!");
startSignal.await();
System.out.println(Thread.currentThread().getName() + "正在全力冲刺");
System.out.println(Thread.currentThread().getName() + " 到达终点");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
endSignal.countDown();
}
});
}
Thread.sleep(1000);
System.out.println("裁判员发号施令啦!!!");
startSignal.countDown();
endSignal.await();
System.out.println("所有运动员到达终点,比赛结束!");
executorService.shutdown(); }
}

输出结果:

pool-1-thread-2 运动员就位等待裁判员响哨!!!
pool-1-thread-1 运动员就位等待裁判员响哨!!!
pool-1-thread-4 运动员就位等待裁判员响哨!!!
pool-1-thread-3 运动员就位等待裁判员响哨!!!
pool-1-thread-5 运动员就位等待裁判员响哨!!!
pool-1-thread-6 运动员就位等待裁判员响哨!!!
裁判员发号施令啦!!!
pool-1-thread-2正在全力冲刺
pool-1-thread-2 到达终点
pool-1-thread-3正在全力冲刺
pool-1-thread-3 到达终点
pool-1-thread-4正在全力冲刺
pool-1-thread-4 到达终点
pool-1-thread-5正在全力冲刺
pool-1-thread-5 到达终点
pool-1-thread-1正在全力冲刺
pool-1-thread-1 到达终点
pool-1-thread-6正在全力冲刺
pool-1-thread-6 到达终点
所有运动员到达终点,比赛结束!

该示例代码中设置了两个CountDownLatch,第一个 endSignal 用于控制让main线程(裁判员)必须等到其他线程(运动员)让CountDownLatch维护的
数值N减到0为止。另一个 startSignal 用于让main线程对其他线程进行“发号施令”,startSignal引用的CountDownLatch初始值为1,而其他线程执行的
run方法中都会先通过 startSignal.await() 让这些线程都被阻塞,直到main线程通过调用 startSignal.countDown(); ,将值N减
1,CountDownLatch维护的数值N为0后,其他线程才能往下执行,并且,每个线程执行的run方法中都会通
过 endSignal.countDown(); 对 endSignal 维护的数值进行减一,由于往线程池提交了6个任务,会被减6次,所以 endSignal 维护的值最终会变为0,
因此main线程在 latch.await(); 阻塞结束,才能继续往下执行。
另外,需要注意的是,当调用CountDownLatch的countDown方法时,当前线程是不会被阻塞,会继续往下执行,比如在该例中会继续输出 pool-1-
thread-4 到达终点 。

example2

模拟数据量较大 多线程分页查询处理

package com.example.demo.test;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; /**
* CountDownLatch 的使用示例
* @version V1.0 10:51 guozl
* @since 1.0
*/
public class CountDownLatchExample {
// 请求的数量(每页数量)
private static final int threadCount = 8; public static void main(String[] args) throws InterruptedException {
//定义j为页数
for (int j = 1; j < 3; j++) {
ExecutorService threadPool = Executors.newFixedThreadPool(5);
final CountDownLatch countDownLatch = new CountDownLatch(threadCount);
for (int i = 0; i < threadCount; i++) {
final int threadnum = i;
threadPool.execute(() -> {// Lambda 表达式的运用
try {
//实际业务操作
test(threadnum);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
countDownLatch.countDown();// 表示一个请求已经被完成
}
});
}
countDownLatch.await();
threadPool.shutdown();
System.out.println("finish");
}
System.out.println("all finish");
System.out.println("处理所有数据业务操作");
} public static void test(int threadnum) throws InterruptedException {
Thread.sleep(500);// 模拟请求的耗时操作
System.out.println("threadnum:" + threadnum);
Thread.sleep(500);// 模拟请求的耗时操作
}
} 执行结果:

threadnum:4
threadnum:2
threadnum:3
threadnum:0
threadnum:1
threadnum:7
threadnum:6
threadnum:5
finish
threadnum:2
threadnum:4
threadnum:0
threadnum:1
threadnum:3
threadnum:7
threadnum:6
threadnum:5
finish
all finish
处理所有数据业务操作

 

下一篇分享循环栅栏:CyclicBarrier  并与CountDownLatch做比较  有问题欢迎评论区交流 共同进步。

倒计时器CountDownLatch的更多相关文章

  1. 多线程之倒计时器CountDownLatch和循环栅栏CyclicBarrier

    1.倒计时器CountDownLatch CountDownLatch是一个多线程控制工具类.通常用来控制线程等待,它可以让一个线程一直等待知道计时结束才开始执行 构造函数: public Count ...

  2. Java基础教程:多线程基础(5)——倒计时器(CountDownLatch)

    Java基础教程:多线程基础(5)——倒计时器(CountDownLatch) 引入倒计时器 在多线程协作完成业务功能时,有时候需要等待其他多个线程完成任务之后,主线程才能继续往下执行业务功能,在这种 ...

  3. 多线程控制工具类--倒计时器CountDownLatch的使用(模仿火箭发射)

    package com.thread.test.Lock; import java.util.Random; import java.util.concurrent.CountDownLatch; i ...

  4. 23.倒计时器CountDownLatch

    门闩是concurrent包中定义的一个类型,是用于多线程通讯的一个辅助类型. 门闩相当于在一个门上加多个锁,当线程调用await方法时,会检查门闩数量,如果门闩数量大于0,线程会阻塞等待. 当线程调 ...

  5. 倒计时器CountDownLatch与同步屏障CyclicBarrier

    CountDownLatch CountDownLatch是一个非常实用的多线程控制工具类,这个工具通常用来控制线程等待,它可以让某一个线程等待直到倒计时结束,再开始执行.在这里指CountDownL ...

  6. 3.1.5 倒计时器:CountDownLatch

    package 第三章.倒计时器CountDownLatch; import java.util.concurrent.CountDownLatch; /** * Created by zzq on ...

  7. 线程工具类 - CountDownLatch(倒计时器)

    CountDownLatch官方文档 一.原理 CountDownLatch是一个非常实用的多线程控制工具类.Count Down在英文中意为倒计时,Latch意为门闩,可以简单的将CountDown ...

  8. Android倒计时器——CountDownTimer

    Android倒计时器--CountDownTimer 说明 第一个参数是倒计时的时间 第二个参数是多长时间执行一次回调 /** * @param millisInFuture The number ...

  9. 【JavaScript】分秒倒计时器

    一.基本目标 在JavaScript设计一个分秒倒计时器,一旦时间完毕使button变成不可点击状态 详细效果例如以下图.为了说明问题.调成每50毫秒也就是每0.05跳一次表, 真正使用的时候,把wi ...

随机推荐

  1. nginx 命令行参数 启动 重启 重载 停止

    今天和大家分享关于 nginx 的一些参数使用 首先,你应该安装了nginx CentOS 安装 nginx 这是很早之前的一篇博客,可以参考. 之前,我们如何去操作 nginx ##简单粗暴法 pk ...

  2. java反序列化-ysoserial-调试分析总结篇(6)

    前言: 这篇记录CommonsCollections6的调试,外层也是新的类,换成了hashset,即从hashset触发其readObject(),yso给的调用链如下图所示 利用链分析: 首先在h ...

  3. Web环境从Apache转Nginx后页面报404错误

    问题原因: Apache支持伪静态规则在项目的入口目录有个.htaccess文件,Apache默认识别此文件内容, 但是Nginx不识别.htaccess文件,导致伪静态规则失效,从而无法解析url地 ...

  4. 为XHR对象所有方法和属性提供钩子 全局拦截AJAX

    摘要 ✨长文 阅读约需十分钟 ✨跟着走一遍需要一小时以上 ✨约100行代码 前段时间打算写一个给手机端用的假冒控制台 可以用来看console的输出 这一块功能目前已经完成了 但是后来知道有一个腾讯团 ...

  5. JZOJ 1736. 扑克游戏 (Standard IO)

    1736. 扑克游戏 (Standard IO) Time Limits: 1000 ms Memory Limits: 128000 KB Description 有一棵无穷大的满二叉树,根为sta ...

  6. 通过filebeat、logstash、rsyslog采集nginx日志的几种方式

    由于nginx功能强大,性能突出,越来越多的web应用采用nginx作为http和反向代理的web服务器.而nginx的访问日志不管是做用户行为分析还是安全分析都是非常重要的数据源之一.如何有效便捷的 ...

  7. Adobe Premiere Pro 2020破解教程

    首先官网下载Adobe Creative Cloud,安装完之后使用它继续安装Pr.注意在安装之前,点击文件→首选项,先设置一下你的安装路径,没有设置则默认安装在C盘. 接着下载网上良心博主推荐的破解 ...

  8. POJ 1879

    栈和队列的综合应用,利用栈和队列分别模拟分,5分,时槽,以及小球队列 利用求出一天后的置换可以求出周期,进而求出最大公约数(可以利用矩阵的角度,也许可以简化,因为每次都是乘上一个相同的置换矩阵) 要注 ...

  9. (转)协议森林06 瑞士军刀 (ICMP协议)

    协议森林06 瑞士军刀 (ICMP协议) 作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 到现在为止,我们讲解了网络层中最重要的I ...

  10. 初识Flask、快速启动

    目录 一.初识Flask 1.1 什么是flask? 1.2 为什么要有flask? 二.Flask快速启动 一.初识Flask 1.1 什么是flask? Flask 本是作者 Armin Rona ...