CountDownLatch是什么

CountDownLatch,英文翻译为倒计时锁存器,是一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。

闭锁可以延迟线程的进度直到其到达终止状态,闭锁可以用来确保某些活动直到其他活动都完成才继续执行:

  • 确保某个计算在其需要的所有资源都被初始化之后才继续执行;
  • 确保某个服务在其依赖的所有其他服务都已经启动之后才启动;
  • 等待直到某个操作所有参与者都准备就绪再继续执行。

CountDownLatch有一个正数计数器,countDown()方法对计数器做减操作,await()方法等待计数器达到0。所有await的线程都会阻塞直到计数器为0或者等待线程中断或者超时。

闭锁(倒计时锁)主要用来保证完成某个任务的先决条件满足。是一个同步工具类,用来协调多个线程之间的同步。这个工具通常用来控制线程等待,它可以让某一个线程等待直到倒计时结束,再开始执行。

CountDownLatch 的两种典型用法

一:某一线程在开始运行前等待n个线程执行完毕。

将 CountDownLatch 的计数器初始化为n :new CountDownLatch(n),每当一个任务线程执行完毕,就将计数器减1 countdownlatch.countDown(),当计数器的值变为0时,在CountDownLatch上 await() 的线程就会被唤醒。一个典型应用场景就是启动一个服务时,主线程需要等待多个组件加载完毕,之后再继续执行。

二:实现多个线程开始执行任务的最大并行性。

注意是并行性,不是并发,强调的是多个线程在某一时刻同时开始执行。类似于赛跑,将多个线程放到起点,等待发令枪响,然后同时开跑。做法是初始化一个共享的 CountDownLatch 对象,将其计数器初始化为 1 :new CountDownLatch(1),多个线程在开始执行任务前首先 coundownlatch.await(),当主线程调用 countDown() 时,计数器变为0,多个线程同时被唤醒。

CountDownLatch 方法示例

方法功能:模拟项目完成--3个同事做ui,做完ui给另外2个同事做前端:
主线程
package CountDownLatchTest;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; /**
* @Description:模拟项目完成--3个同事做ui,做完ui给另外2个同事做前端:
* 要求UI将图片全部画完之后 才能交付给前端
* @Param:
* @return:
* @Date: 2019/9/17
*/
public class CountDownLatchDemo { public static void main(String[] args) {
CountDownLatch UIcountDownLatch =new CountDownLatch(3);
CountDownLatch JScountDownLatch =new CountDownLatch(2); System.out.println("项目开始做了");
ExecutorService executor=Executors.newFixedThreadPool(5);
UIPeople uiPeople=new UIPeople(UIcountDownLatch);
JSPeople jsPeople=new JSPeople(JScountDownLatch);
try {
//3个UI开始工作
for (int i = 0; i <3 ; i++) {
executor.submit(uiPeople);
}
// 等待3个UI工作进行完成
UIcountDownLatch.await();
System.out.println("UI工作全部完成");
//2个前端开始工作
for (int i = 0; i <2 ; i++) {
executor.submit(jsPeople);
}
// 等待2个前端工作进行完成
JScountDownLatch.await();
System.out.println("前端工作全部完成");
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("项目做完了");
}
}

UI工作人员类

package CountDownLatchTest;

import java.util.Random;
import java.util.concurrent.CountDownLatch; public class UIPeople implements Runnable {
private CountDownLatch latch; public UIPeople(CountDownLatch latch) {
this.latch = latch;
} @Override
public void run() {
try {
long start = System.currentTimeMillis();
Thread.sleep(new Random().nextInt(10)*1000);
long end = System.currentTimeMillis();
System.out.println(Thread.currentThread().getName()+"界面画完了用时:"+(end-start)+"ms");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
//工做做完了计时器减一
latch.countDown();
}
}
}

前端工作人员

package CountDownLatchTest;

import java.util.Random;
import java.util.concurrent.CountDownLatch; /**
* @Description: 前端人员
* @Param:
* @return:
* @Date: 2019/9/17
*/
public class JSPeople implements Runnable{ private CountDownLatch latch; public JSPeople(CountDownLatch latch) {
this.latch = latch;
}
@Override
public void run() {
try {
long start = System.currentTimeMillis();
Thread.sleep(new Random().nextInt(10)*1000);
long end = System.currentTimeMillis();
System.out.println(Thread.currentThread().getName()+"根据图片将前端页面画完了:"+(end-start)+"ms");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
//工做做完了计时器减一
latch.countDown();
}
}
}
上面示例解释

首先使用5个线程池表示5个人员,2个CountDownLatch表示前端人员和UI人员的工作,首先UI人员进行工作,因为每个人员工作时间是不一样的,但是不管他们工作时间的长短,都会停在UIcountDownLatch.await()这个方法,
等待所有的UI人员工作进行完成,而我们是怎么职到UI人员是怎么做的呢?由上面代码可知在UI成员的线程的任务里最后都执行到latch.countDown()时,在调用这个方法时主线程的计数器会减一,当主线程的countDownLatch
计数器为0时,代表所有的UI成员任务都执行成功了,然后主线程继续执行下一步,前端人员同理。

CyclicBarrier简介

CyclicBarrier,是JDK1.5的java.util.concurrent并发包中提供的一个并发工具类。

所谓Cyclic即 循环 的意思,所谓Barrier即 屏障 的意思。

所以综合起来,CyclicBarrier指的就是 循环屏障,虽然这个叫法很奇怪,但是确能很好地表示它的作用。

CyclicBarrier方法说明

——CyclicBarrier(parties)

  初始化相互等待的线程数量的构造方法。

——CyclicBarrier(parties,Runnable barrierAction)

  初始化相互等待的线程数量以及屏障线程的构造方法。

屏障线程的运行时机:等待的线程数量=parties之后,CyclicBarrier打开屏障之前。

举例:在分组计算中,每个线程负责一部分计算,最终这些线程计算结束之后,交由屏障线程进行汇总计算。

——getParties()

  获取CyclicBarrier打开屏障的线程数量,也成为方数。

——getNumberWaiting()

  获取正在CyclicBarrier上等待的线程数量。

——await()

  在CyclicBarrier上进行阻塞等待,直到发生以下情形之一:

  • 在CyclicBarrier上等待的线程数量达到parties,则所有线程被释放,继续执行。
  • 当前线程被中断,则抛出InterruptedException异常,并停止等待,继续执行。
  • 其他等待的线程被中断,则当前线程抛出BrokenBarrierException异常,并停止等待,继续执行。
  • 其他等待的线程超时,则当前线程抛出BrokenBarrierException异常,并停止等待,继续执行。
  • 其他线程调用CyclicBarrier.reset()方法,则当前线程抛出BrokenBarrierException异常,并停止等待,继续执行。

——await(timeout,TimeUnit)

  在CyclicBarrier上进行限时的阻塞等待,直到发生以下情形之一:

  • 在CyclicBarrier上等待的线程数量达到parties,则所有线程被释放,继续执行。
  • 当前线程被中断,则抛出InterruptedException异常,并停止等待,继续执行。
  • 当前线程等待超时,则抛出TimeoutException异常,并停止等待,继续执行。
  • 其他等待的线程被中断,则当前线程抛出BrokenBarrierException异常,并停止等待,继续执行。
  • 其他等待的线程超时,则当前线程抛出BrokenBarrierException异常,并停止等待,继续执行。
  • 其他线程调用CyclicBarrier.reset()方法,则当前线程抛出BrokenBarrierException异常,并停止等待,继续执行。

——isBroken()

  获取是否破损标志位broken的值,此值有以下几种情况:

  • CyclicBarrier初始化时,broken=false,表示屏障未破损。
  • 如果正在等待的线程被中断,则broken=true,表示屏障破损。
  • 如果正在等待的线程超时,则broken=true,表示屏障破损。
  • 如果有线程调用CyclicBarrier.reset()方法,则broken=false,表示屏障回到未破损状态。

——reset()

  使得CyclicBarrier回归初始状态,直观来看它做了两件事:

  • 如果有正在等待的线程,则会抛出BrokenBarrierException异常,且这些线程停止等待,继续执行。
  • 将是否破损标志位broken置为false。

CyclicBarrier方法练习

主线程

package CyclicBarrierTest;

import javafx.concurrent.Worker;

import java.util.concurrent.CyclicBarrier;

/**
* @Description:
* @Param:
* @return: 一个会议要等10个人都在的时候才能开始开
* @Date: 2019/9/17
*/
public class CyclicBarrierDemo {
public static void main(String[] args) {
CyclicBarrier cyclicBarrier=new CyclicBarrier(10); for (int i = 0; i < 10; i++) {
System.out.println("开始进场" + i);
People people = new People(cyclicBarrier);
new Thread(people).start();
} }
}

人员类

package CyclicBarrierTest;

import java.util.concurrent.CyclicBarrier;

public class People implements Runnable {

    private CyclicBarrier cyclicBarrier;

    public People(CyclicBarrier cyclicBarrier) {
this.cyclicBarrier = cyclicBarrier;
} @Override
public void run() {
try {
System.out.println(Thread.currentThread().getName() + "进成功开始等待其他人,当前有"+cyclicBarrier.getNumberWaiting()+"人在等待");
cyclicBarrier.await();
System.out.println(Thread.currentThread().getName() + "开始开会");
// 工作线程开始处理,这里用Thread.sleep()来模拟业务处理
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + "开会完毕");
} catch (Exception e) {
e.printStackTrace();
} }
}

执行结果

D:\java\jdk1.8\bin\java.exe "-javaagent:D:\ideaa\IntelliJ IDEA 2018.1.2\lib\idea_rt.jar=57236:D:\ideaa\IntelliJ IDEA 2018.1.2\bin" -Dfile.encoding=UTF-8 -classpath D:\java\jdk1.8\jre\lib\charsets.jar;D:\java\jdk1.8\jre\lib\deploy.jar;D:\java\jdk1.8\jre\lib\ext\access-bridge-32.jar;D:\java\jdk1.8\jre\lib\ext\cldrdata.jar;D:\java\jdk1.8\jre\lib\ext\dnsns.jar;D:\java\jdk1.8\jre\lib\ext\jaccess.jar;D:\java\jdk1.8\jre\lib\ext\jfxrt.jar;D:\java\jdk1.8\jre\lib\ext\localedata.jar;D:\java\jdk1.8\jre\lib\ext\nashorn.jar;D:\java\jdk1.8\jre\lib\ext\sunec.jar;D:\java\jdk1.8\jre\lib\ext\sunjce_provider.jar;D:\java\jdk1.8\jre\lib\ext\sunmscapi.jar;D:\java\jdk1.8\jre\lib\ext\sunpkcs11.jar;D:\java\jdk1.8\jre\lib\ext\zipfs.jar;D:\java\jdk1.8\jre\lib\javaws.jar;D:\java\jdk1.8\jre\lib\jce.jar;D:\java\jdk1.8\jre\lib\jfr.jar;D:\java\jdk1.8\jre\lib\jfxswt.jar;D:\java\jdk1.8\jre\lib\jsse.jar;D:\java\jdk1.8\jre\lib\management-agent.jar;D:\java\jdk1.8\jre\lib\plugin.jar;D:\java\jdk1.8\jre\lib\resources.jar;D:\java\jdk1.8\jre\lib\rt.jar;E:\gyf\target\classes CyclicBarrierTest.CyclicBarrierDemo
开始进场0
开始进场1
开始进场2
开始进场3
开始进场4
开始进场5
开始进场6
开始进场7
开始进场8
开始进场9
Thread-0进成功开始等待其他人,当前有0人在等待
Thread-4进成功开始等待其他人,当前有1人在等待
Thread-8进成功开始等待其他人,当前有2人在等待
Thread-1进成功开始等待其他人,当前有3人在等待
Thread-5进成功开始等待其他人,当前有4人在等待
Thread-9进成功开始等待其他人,当前有5人在等待
Thread-3进成功开始等待其他人,当前有6人在等待
Thread-7进成功开始等待其他人,当前有7人在等待
Thread-2进成功开始等待其他人,当前有8人在等待
Thread-6进成功开始等待其他人,当前有9人在等待
Thread-6开始开会
Thread-0开始开会
Thread-4开始开会
Thread-8开始开会
Thread-1开始开会
Thread-5开始开会
Thread-9开始开会
Thread-3开始开会
Thread-7开始开会
Thread-2开始开会
Thread-6开会完毕
Thread-7开会完毕
Thread-2开会完毕
Thread-4开会完毕
Thread-0开会完毕
Thread-3开会完毕
Thread-5开会完毕
Thread-8开会完毕
Thread-9开会完毕
Thread-1开会完毕 Process finished with exit code 0

上面是模拟10个人一起开会的情况,当第一个线程到最后第一个线程开始执行后,都会等待后续线程到达cyclicBarrier.await()时会停驶当前线程的任务,当所有线程执行到await时,并行开始进行下一布任务

CountDownLatch与CyclicBarrier的区别:

CountDownLatch是一个同步的辅助类,允许一个或多个线程,等待其他一组线程完成操作,再继续执行。 
CyclicBarrier是一个同步的辅助类,允许一组线程相互之间等待,达到一个共同点,再继续执行。 
区别:

    • CountDownLatch的计数器只能使用一次。而CyclicBarrier的计数器可以使用reset() 方法重置。所以CyclicBarrier能处理更为复杂的业务场景,比如如果计算发生错误,可以重置计数器,并让线程们重新执行一次
    • CyclicBarrier还提供getNumberWaiting(可以获得CyclicBarrier阻塞的线程数量)、isBroken(用来知道阻塞的线程是否被中断)等方法。
    • CountDownLatch会阻塞主线程,CyclicBarrier不会阻塞主线程,只会阻塞子线程。

JAVA并发工具类---------------(CountDownLatch和CyclicBarrier)的更多相关文章

  1. 25.大白话说java并发工具类-CountDownLatch,CyclicBarrier,Semaphore,Exchanger

    1. 倒计时器CountDownLatch 在多线程协作完成业务功能时,有时候需要等待其他多个线程完成任务之后,主线程才能继续往下执行业务功能,在这种的业务场景下,通常可以使用Thread类的join ...

  2. Java 并发工具类 CountDownLatch、CyclicBarrier、Semaphore、Exchanger

    本文部分摘自<Java 并发编程的艺术> CountDownLatch CountDownLatch 允许一个或多个线程等待其他线程完成操作.假设现有一个需求:我们需要解析一个 Excel ...

  3. Java并发工具类 - CountDownLatch

    Java并发工具类 - CountDownLatch 1.简介 CountDownLatch是Java1.5之后引入的Java并发工具类,放在java.util.concurrent包下面 http: ...

  4. Java并发工具类CountDownLatch源码中的例子

    Java并发工具类CountDownLatch源码中的例子 实例一 原文描述 /** * <p><b>Sample usage:</b> Here is a pai ...

  5. java 并发工具类CountDownLatch & CyclicBarrier

    一起在java1.5被引入的并发工具类还有CountDownLatch.CyclicBarrier.Semaphore.ConcurrentHashMap和BlockingQueue,它们都存在于ja ...

  6. Java中的并发工具类(CountDownLatch、CyclicBarrier、Semaphore、Exchanger)

    在JDK的并发包里提供了很多有意思的并发工具类.CountDownLatch.CyclicBarrier和Semaphore 工具类提供了一种并发流程控制的手段,Exchanger 工具类则提供了在线 ...

  7. java多线程10:并发工具类CountDownLatch、CyclicBarrier和Semaphore

    在JDK的并发包(java.util.concurrent下)中给开发者提供了几个非常有用的并发工具类,让用户不需要再去关心如何在并发场景下写出同时兼顾线程安全性与高效率的代码. 本文分别介绍Coun ...

  8. 多线程学习笔记六之并发工具类CountDownLatch和CyclicBarrier

    目录 简介 CountDownLatch 示例 实现分析 CountDownLatch与Thread.join() CyclicBarrier 实现分析 CountDownLatch和CyclicBa ...

  9. 1.3.4 并发工具类CountDownLatch/Semaphore/CyclicBarrier/FutureTask

    CountDownLatch的2个用途: 1. 所有线程都到达相同的起跑线后,再一起开始跑(并非同时开始,而是队列中一个唤醒另一个)[此情况需到达起跑线后再调用await()等待其他线程] 2. 所有 ...

随机推荐

  1. sql server 基础语法4 实践练习+子查询

    drop table class create table class ( classId ) primary key not null, cName ) ) insert into class ', ...

  2. Database基础(四):密码恢复及设置、 用户授权及撤销、数据备份与恢复、MySQL管理工具

    一.密码恢复及设置 目标: 本案例要求熟悉MySQL管理密码的控制,完成以下任务操作: 练习重置MySQL管理密码的操作 通过正常途径设置MySQL数据库的管理密码 步骤: 步骤一:重置MySQL管理 ...

  3. ShellListView

    過濾ShellListView顯示的檔案 有關這方面的元件你可以在Win3.中找到相關元件 你可以使用四個元件搭配應該就可以你所需要的功能 DriveComboBox1.FilterComboBox1 ...

  4. 【从0到1,搭建Spring Boot+RESTful API+Shiro+Mybatis+SQLServer权限系统】04、统一处理异常

    本节讨论如何使用Spring的异常处理机制,当我们程序出现错误时,以相同的一种格式,把错误信息返回给客户端 1.创建一些自定义异常 public class TipsException extends ...

  5. Rsync 实现服务器文件的同步——服务端的安装配置

    一.安装rsync 直接使用yum命令进行安装即可. yum -y install rsync 二.配置文件 网上大多教程都说安装是默认没有配置文件的,但是经过我的尝试,yum安装下默认是有配置文件的 ...

  6. HDU1251-统计难题-map+输入

    Ignatius最近遇到一个难题,老师交给他很多单词(只有小写字母组成,不会有重复的单词出现),现在老师要他统计出以某个字符串为前缀的单词数量(单词本身也是自己的前缀). Input输入数据的第一部分 ...

  7. python学习笔记:接口开发——flask Demo实例

    举例1,返回当前时间接口 ''' 初始化:所有的Flask都必须创建程序实例, web服务器使用wsgi协议,把客户端所有的请求都转发给这个程序实例 程序实例是Flask的对象,一般情况下用如下方法实 ...

  8. 在VMware下创建windows2008虚拟机

    1.创建新的虚拟机 打开VMware软件,点击主页内创建新的虚拟机 2.进入新建虚拟机向导 点击典型,点击下一步 3.在下一步中单击稍后安装操作系统 点击下一步 4.选择操作系统类型 客户机操作系统选 ...

  9. 发布 Vant - 高效的 Vue 组件库,再造一个有赞移动商城也不在话下

    发布 Vant - 高效的 Vue 组件库,再造一个有赞移动商城也不在话下:https://segmentfault.com/a/1190000011377961 vantUI框架在vue项目中的应用 ...

  10. Java7任务并行执行神器:Fork&Join框架

    Fork/Join是什么? Fork/Join框架是Java7提供的并行执行任务框架,思想是将大任务分解成小任务,然后小任务又可以继续分解,然后每个小任务分别计算出结果再合并起来,最后将汇总的结果作为 ...