16_张孝祥_多线程_同步工具CyclicBarrier与CountDownLatch
转载:
CyclicBarrier的用法
CountDownLatch(倒计时计数器)使用说明
参考:
CyclicBarrier和CountDownLatch区别
CyclicBarrier
CyclicBarrier是一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier。
CyclicBarrier类似于CountDownLatch也是个计数器, 不同的是CyclicBarrier数的是调用了CyclicBarrier.await()进入等待的线程数, 当线程数达到了CyclicBarrier初始时规定的数目时,所有进入等待状态的线程被唤醒并继续。 CyclicBarrier就象它名字的意思一样,可看成是个障碍, 所有的线程必须到齐后才能一起通过这个障碍。 CyclicBarrier初始时还可带一个Runnable的参数,此Runnable任务在CyclicBarrier的数目达到后,所有其它线程被唤醒前被执行。
构造方法摘要
构造方法摘要 |
---|
CyclicBarrier(int parties) 创建一个新的 CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,但它不会在每个 barrier 上执行预定义的操作。 |
CyclicBarrier(int parties, Runnable barrierAction) 创建一个新的 CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,并在启动 barrier 时执行给定的屏障操作,该操作由最后一个进入 barrier 的线程执行 |
方法摘要
返回值 | 方法 |
---|---|
int | await() 在所有参与者都已经在此 barrier 上调用 await 方法之前,将一直等待。 |
int | await(long timeout, TimeUnit unit) 在所有参与者都已经在此屏障上调用 await 方法之前,将一直等待。 |
int | getNumberWaiting() 返回当前在屏障处等待的参与者数目。 |
int | getParties() 返回要求启动此 barrier 的参与者数目。 |
boolean | isBroken() 查询此屏障是否处于损坏状态。 |
void | reset() 将屏障重置为其初始状态。 |
代码示例
示例一:
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;public class CyclicBarrierTest {public static void main(String[] args) {ExecutorService service = Executors.newCachedThreadPool();final CyclicBarrier cb = new CyclicBarrier(3);//创建CyclicBarrier对象并设置3个公共屏障点for(int i=0;i<3;i++){Runnable runnable = new Runnable(){public void run(){try {Thread.sleep((long)(Math.random()*10000)); System.out.println("线程" + Thread.currentThread().getName() + "即将到达集合地点1,当前已有" + cb.getNumberWaiting() + "个已经到达,正在等候"); cb.await();//到此如果没有达到公共屏障点,则该线程处于等待状态,如果达到公共屏障点则所有处于等待的线程都继续往下运行Thread.sleep((long)(Math.random()*10000)); System.out.println("线程" + Thread.currentThread().getName() + "即将到达集合地点2,当前已有" + cb.getNumberWaiting() + "个已经到达,正在等候"); cb.await(); Thread.sleep((long)(Math.random()*10000)); System.out.println("线程" + Thread.currentThread().getName() + "即将到达集合地点3,当前已有" + cb.getNumberWaiting() + "个已经到达,正在等候"); cb.await(); } catch (Exception e) {e.printStackTrace();} }};service.execute(runnable);}service.shutdown();}
}
输出:
线程pool-1-thread-2即将到达集合地点1,当前已有0个已经到达,正在等候
线程pool-1-thread-1即将到达集合地点1,当前已有1个已经到达,正在等候
线程pool-1-thread-3即将到达集合地点1,当前已有2个已经到达,正在等候
线程pool-1-thread-3即将到达集合地点2,当前已有0个已经到达,正在等候
线程pool-1-thread-1即将到达集合地点2,当前已有1个已经到达,正在等候
线程pool-1-thread-2即将到达集合地点2,当前已有2个已经到达,正在等候
线程pool-1-thread-3即将到达集合地点3,当前已有0个已经到达,正在等候
线程pool-1-thread-2即将到达集合地点3,当前已有1个已经到达,正在等候
线程pool-1-thread-1即将到达集合地点3,当前已有2个已经到达,正在等候
示例二:
如果在构造CyclicBarrier对象的时候传了一个Runnable对象进去,则每次到达公共屏障点的时候都最先执行这个传进去的Runnable,然后再执行处于等待的Runnable。如果把上面的例子改成下面这样:
package com.thread;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;public class CyclicBarrierTest {public static void main(String[] args) {ExecutorService service = Executors.newCachedThreadPool();//final CyclicBarrier cb = new CyclicBarrier(3);//创建CyclicBarrier对象并设置3个公共屏障点final CyclicBarrier cb = new CyclicBarrier(3,new Runnable(){@Overridepublic void run() {System.out.println("********我最先执行***********");}});for(int i=0;i<3;i++){Runnable runnable = new Runnable(){public void run(){try {Thread.sleep((long)(Math.random()*10000)); System.out.println("线程" + Thread.currentThread().getName() + "即将到达集合地点1,当前已有" + cb.getNumberWaiting() + "个已经到达,正在等候"); cb.await();//到此如果没有达到公共屏障点,则该线程处于等待状态,如果达到公共屏障点则所有处于等待的线程都继续往下运行Thread.sleep((long)(Math.random()*10000)); System.out.println("线程" + Thread.currentThread().getName() + "即将到达集合地点2,当前已有" + cb.getNumberWaiting() + "个已经到达,正在等候"); cb.await(); //这里CyclicBarrier对象又可以重用Thread.sleep((long)(Math.random()*10000)); System.out.println("线程" + Thread.currentThread().getName() + "即将到达集合地点3,当前已有" + cb.getNumberWaiting() + "个已经到达,正在等候"); cb.await(); } catch (Exception e) {e.printStackTrace();} }};service.execute(runnable);}service.shutdown();}
}
结果
线程pool-1-thread-1即将到达集合地点1,当前已有0个已经到达,正在等候
线程pool-1-thread-3即将到达集合地点1,当前已有1个已经到达,正在等候
线程pool-1-thread-2即将到达集合地点1,当前已有2个已经到达,正在等候
********我最先执行***********
线程pool-1-thread-1即将到达集合地点2,当前已有0个已经到达,正在等候
线程pool-1-thread-3即将到达集合地点2,当前已有1个已经到达,正在等候
线程pool-1-thread-2即将到达集合地点2,当前已有2个已经到达,正在等候
********我最先执行***********
线程pool-1-thread-1即将到达集合地点3,当前已有0个已经到达,正在等候
线程pool-1-thread-3即将到达集合地点3,当前已有1个已经到达,正在等候
线程pool-1-thread-2即将到达集合地点3,当前已有2个已经到达,正在等候
********我最先执行***********
CountDownLatch
一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。
用给定的计数 初始化 CountDownLatch。由于调用了 countDown() 方法,所以在当前计数到达零之前,await 方法会一直受阻塞。之后,会释放所有等待的线程,await 的所有后续调用都将立即返回。这种现象只出现一次——计数无法被重置。如果需要重置计数,请考虑使用 CyclicBarrier。
CountDownLatch 是一个通用同步工具,它有很多用途。将计数 1 初始化的 CountDownLatch 用作一个简单的开/关锁存器,或入口:在通过调用 countDown() 的线程打开入口前,所有调用 await 的线程都一直在入口处等待。用 N 初始化的 CountDownLatch 可以使一个线程在 N 个线程完成某项操作之前一直等待,或者使其在某项操作完成 N 次之前一直等待。
CountDownLatch 的一个有用特性是,它不要求调用 countDown 方法的线程等到计数到达零时才继续,而在所有线程都能通过之前,它只是阻止任何线程继续通过一个 await。
构造方法摘要
CountDownLatch(int count) 构造一个用给定计数初始化的 CountDownLatch。
方法摘要
返回值 | 方法 |
---|---|
void | await() 使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断。 |
boolean | await(long timeout, TimeUnit unit) 使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断或超出了指定的等待时间。 |
void | countDown() 递减锁存器的计数,如果计数到达零,则释放所有等待的线程。 |
long | getCount() 返回当前计数。 |
String | toString() 返回标识此锁存器及其状态的字符串。 |
代码示例
一种典型用法是,将一个问题分成 N 个部分,用执行每个部分并让锁存器倒计数的 Runnable 来描述每个部分,然后将所有 Runnable 加入到 Executor 队列。当所有的子部分完成后,协调线程就能够通过 await。(当线程必须用这种方法反复倒计数时,可改为使用 CyclicBarrier。)
示例一:
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class CountdownLatchTest1 {public static void main(String[] args) {ExecutorService service = Executors. newFixedThreadPool(3);final CountDownLatch latch = new CountDownLatch(3);for (int i = 0; i < 3; i++) {Runnable runnable = new Runnable() {@Overridepublic void run() {try {System. out.println("子线程" + Thread.currentThread().getName() + "开始执行");Thread. sleep((long) (Math. random() * 10000));System. out.println("子线程" + Thread.currentThread().getName() + "执行完成");latch.countDown(); // 当前线程调用此方法,则计数减一} catch (InterruptedException e) {e.printStackTrace();}}};service.execute(runnable);}try {System. out.println("主线程" + Thread.currentThread().getName() + "等待子线程执行完成..." );latch.await(); // 阻塞当前线程,直到计时器的值为0System. out.println("主线程" + Thread.currentThread().getName() + "开始执行...");} catch (InterruptedException e) {e.printStackTrace();}}
}
示例二:百米赛跑,4名运动员选手到达场地等待裁判口令,裁判一声口令,选手听到后同时起跑,当所有选手到达终点,裁判进行汇总汇总排名。
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class CountdownLatchTest2 {public static void main(String[] args) {ExecutorService service = Executors. newCachedThreadPool();final CountDownLatch cdOrder = new CountDownLatch(1);final CountDownLatch cdAnswer = new CountDownLatch(4);for (int i = 0; i < 4; i++) {Runnable runnable = new Runnable() {public void run() {try {System. out.println("选手" + Thread.currentThread().getName() + "正等待裁判发布口令");cdOrder.await();System. out.println("选手" + Thread.currentThread().getName() + "已接受裁判口令");Thread. sleep((long) (Math. random() * 10000));System. out.println("选手" + Thread.currentThread().getName() + "到达终点");cdAnswer.countDown();} catch (Exception e) {e.printStackTrace();}}};service.execute(runnable);}try {Thread. sleep((long) (Math. random() * 10000));System. out.println("裁判" + Thread.currentThread ().getName() + "即将发布口令" );cdOrder.countDown();System. out.println("裁判" + Thread.currentThread ().getName() + "已发送口令,正在等待所有选手到达终点" );cdAnswer.await();System. out.println("所有选手都到达终点" );System. out.println("裁判" + Thread.currentThread ().getName() + "汇总成绩排名" );} catch (Exception e) {e.printStackTrace();}service.shutdown();}
}
CountDownLatch与CyclicBarrier对比
CountDownLatch | CyclicBarrier |
---|---|
减计数方式 | 加计数方式 |
计算为0时释放所有等待的线程 | 计数达到指定值时释放所有等待线程 |
计数为0时,无法重置 | 计数达到指定值时,计数置为0重新开始 |
调用countDown()方法计数减一,调用await()方法只进行阻塞,对计数没任何影响 | 调用await()方法计数加1,若加1后的值不等于构造方法的值,则线程阻塞 |
不可重复利用 | 可重复利用 |
16_张孝祥_多线程_同步工具CyclicBarrier与CountDownLatch相关推荐
- JAVA入门_多线程_邮局派发信件
JAVA入门_多线程_邮局派发信件 Postman package cn.campsg.java.experiment.entity;public class Postman {private Str ...
- 11_张孝祥_多线程_线程锁技术
转载 Java并发编程:Lock locks相关类 锁相关的类都在包java.util.concurrent.locks下,有以下类和接口: |---AbstractOwnableSynchroniz ...
- Java 并发编程之同步工具类闭锁 CountDownLatch
Java 同步工具类CountDownLatch相当于一个计数器,假设一个方法,等待一个计数器从初始值5变为0,每使用一次countdown()方法,计数器的值减少1,当计数器的值为0时,触发某件事. ...
- java runnable线程锁_多线程 java 同步 、锁 、 synchronized 、 Thread 、 Runnable
线程 1 线程概述 1.1 什么是线程 v 线程是程序执行的一条路径, 一个进程中可以包含多条线程 v 一个应用程序可以理解成就是一个进程 v 多线程并发执行可以提高程序的效率, 可以同时完成多 ...
- Java学习笔记18:Java_Map集合_HashMap集合_可变参数_Stream流_多线程_线程同步_生产者消费者
文章目录 1.Map集合 1.1Map集合概述和特点[理解] 1.2Map集合的基本功能[应用] 1.3Map集合的获取功能[应用] 1.4Map集合的遍历(方式1)[应用] 1.5Map集合的遍历( ...
- m3u8转mp4缓存合并工厂_多线程m3u8下载工具,支持windowsamp;amp;linux;两个羊毛线报...
m3u8下载工具还是挺多的,很多也是基于ffmpeg,这个也是. 这个命令行下载工具,支持windows和linux 64位系统. 支持多线程,支持设置header[一些m3u8链接可能需要设置hea ...
- java semaphore 等待时间_一个java同步工具类Semaphore的详解
Semaphore是java并发包里面的一个工具类,我们限制可以访问某些资源的线程数目就可以使用Semaphore了.这篇文章将对Semaphore的概念和使用进行一个详解. 一.概念理解 官方是这样 ...
- linux npm 修改 源_多线程m3u8下载工具,支持windowsamp;amp;linux;两个羊毛线报
m3u8下载工具还是挺多的,很多也是基于ffmpeg,这个也是. 这个命令行下载工具,支持windows和linux 64位系统. 支持多线程,支持设置header[一些m3u8链接可能需要设置hea ...
- 张孝祥 java多线程_张孝祥老师-java并发编程听课笔记(三)
第六讲 ThreadLocal实现线程范围内的共享 ThreadLocal相当于一个哈希 public class ThreadLocalTest{ private static ThreadLoca ...
最新文章
- Window下JDK安装教程
- webservice xml java_java访问WebService接口返回xml
- 用Helper对类的行为进行修饰以便复用(附:外三篇)
- Java的值传递解析
- 数据管理,数据治理,数据中心,数据中台,数据湖这下就分清楚了!
- Ubuntu 完全卸载 Apache2
- python分片的步长_Python的分片操作
- 8-14 领导者选举
- 从CVPR2019 看计算机视觉最新趋势
- 巨详细一文教你如何撰写商业计划书
- css图片滑动切换图_html图片轮播原理
- html 警告图标,HTML+CSS入门 CSS实现核辐射警告标志
- word插入脚注后最后一页多了一个分页符(下一页),导致最后多了一个空白页,删除不掉。
- java 逃逸_Java 逃逸分析
- 防干扰继电器控制电路
- 如何零基础创建自己的微信小程序
- win11文件后缀名怎么查看 Windows11查看文件后缀的设置方法
- 解决U盘文件变成快捷方式的最佳方法
- 方兴东:博客网倒掉是十亿美金的教训
- 问题解决:from conda.cli import main ModuleNotFoundError: No module named 'conda'