转载:
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相关推荐

  1. JAVA入门_多线程_邮局派发信件

    JAVA入门_多线程_邮局派发信件 Postman package cn.campsg.java.experiment.entity;public class Postman {private Str ...

  2. 11_张孝祥_多线程_线程锁技术

    转载 Java并发编程:Lock locks相关类 锁相关的类都在包java.util.concurrent.locks下,有以下类和接口: |---AbstractOwnableSynchroniz ...

  3. Java 并发编程之同步工具类闭锁 CountDownLatch

    Java 同步工具类CountDownLatch相当于一个计数器,假设一个方法,等待一个计数器从初始值5变为0,每使用一次countdown()方法,计数器的值减少1,当计数器的值为0时,触发某件事. ...

  4. java runnable线程锁_多线程 java 同步 、锁 、 synchronized 、 Thread 、 Runnable

    线程 1 线程概述 1.1 什么是线程 v  线程是程序执行的一条路径, 一个进程中可以包含多条线程 v  一个应用程序可以理解成就是一个进程 v  多线程并发执行可以提高程序的效率, 可以同时完成多 ...

  5. Java学习笔记18:Java_Map集合_HashMap集合_可变参数_Stream流_多线程_线程同步_生产者消费者

    文章目录 1.Map集合 1.1Map集合概述和特点[理解] 1.2Map集合的基本功能[应用] 1.3Map集合的获取功能[应用] 1.4Map集合的遍历(方式1)[应用] 1.5Map集合的遍历( ...

  6. m3u8转mp4缓存合并工厂_多线程m3u8下载工具,支持windowsamp;amp;linux;两个羊毛线报...

    m3u8下载工具还是挺多的,很多也是基于ffmpeg,这个也是. 这个命令行下载工具,支持windows和linux 64位系统. 支持多线程,支持设置header[一些m3u8链接可能需要设置hea ...

  7. java semaphore 等待时间_一个java同步工具类Semaphore的详解

    Semaphore是java并发包里面的一个工具类,我们限制可以访问某些资源的线程数目就可以使用Semaphore了.这篇文章将对Semaphore的概念和使用进行一个详解. 一.概念理解 官方是这样 ...

  8. linux npm 修改 源_多线程m3u8下载工具,支持windowsamp;amp;linux;两个羊毛线报

    m3u8下载工具还是挺多的,很多也是基于ffmpeg,这个也是. 这个命令行下载工具,支持windows和linux 64位系统. 支持多线程,支持设置header[一些m3u8链接可能需要设置hea ...

  9. 张孝祥 java多线程_张孝祥老师-java并发编程听课笔记(三)

    第六讲 ThreadLocal实现线程范围内的共享 ThreadLocal相当于一个哈希 public class ThreadLocalTest{ private static ThreadLoca ...

最新文章

  1. Window下JDK安装教程
  2. webservice xml java_java访问WebService接口返回xml
  3. 用Helper对类的行为进行修饰以便复用(附:外三篇)
  4. Java的值传递解析
  5. 数据管理,数据治理,数据中心,数据中台,数据湖这下就分清楚了!
  6. Ubuntu 完全卸载 Apache2
  7. python分片的步长_Python的分片操作
  8. 8-14 领导者选举
  9. 从CVPR2019 看计算机视觉最新趋势
  10. 巨详细一文教你如何撰写商业计划书
  11. css图片滑动切换图_html图片轮播原理
  12. html 警告图标,HTML+CSS入门 CSS实现核辐射警告标志
  13. word插入脚注后最后一页多了一个分页符(下一页),导致最后多了一个空白页,删除不掉。
  14. java 逃逸_Java 逃逸分析
  15. 防干扰继电器控制电路
  16. 如何零基础创建自己的微信小程序
  17. win11文件后缀名怎么查看 Windows11查看文件后缀的设置方法
  18. 解决U盘文件变成快捷方式的最佳方法
  19. 方兴东:博客网倒掉是十亿美金的教训
  20. 问题解决:from conda.cli import main ModuleNotFoundError: No module named 'conda'

热门文章

  1. 小明同学利用计算机软件绘制函数,各地选择题压轴类专题原卷.doc
  2. 基于jsp+mysql+ssm主题酒店预订系统-计算机毕业设计
  3. 自媒体原创视频怎么做?这3个领域无需出镜
  4. 浙江大学计算机电子信息,浙江大学
  5. MATLAB基础学习(五)-MATLAB矩阵介绍
  6. 深入浅出话多态(上)——具体而微
  7. matlab有限元编程实例梁,梁单元有限元计算程序(matlab)
  8. 航信电子发票开发(servlet请求方式)
  9. 预告——看我出招之:苦战samba乱码
  10. Trello进行时间和项目的管理