Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >面试系列之-线程屏障cyclicBarrier(JAVA基础)

面试系列之-线程屏障cyclicBarrier(JAVA基础)

作者头像
用户4283147
发布于 2023-08-21 12:17:10
发布于 2023-08-21 12:17:10
24700
代码可运行
举报
文章被收录于专栏:对线JAVA面试对线JAVA面试
运行总次数:0
代码可运行

概述

是一个同步辅助类,允许一组线程相互等待,直到到达某个公共的屏障点,通过它可以完成多个线程之间相互等待,只有当每个线程都准备就绪后,才能各自继续往下执行后面的操作。

与CountDownLatch有相似的地方,都是使用计数器实现,当某个线程调用了CyclicBarrier的await()方法后,该线程就进入了等待状态,而且计数器执行加1操作,当计数器的值达到了设置的初始值,调用await()方法进入等待状态的线程会被唤醒,继续执行各自后续的操作。CyclicBarrier在释放等待线程后可以重用,所以,CyclicBarrier又被称为循环屏障。

使用场景

可以用于多线程计算数据,最后合并计算结果的场景;

CyclicBarrier与CountDownLatch的区别

CountDownLatch的计数器只能使用一次,而CyclicBarrier的计数器可以使用reset()方法进行重置,并且可以循环使用,CountDownLatch主要实现1个或n个线程需要等待其他线程完成某项操作之后,才能继续往下执行,描述的是1个或n个线程等待其他线程的关系。而CyclicBarrier主要实现了多个线程之间相互等待,直到所有的线程都满足了条件之后,才能继续执行后续的操作,描述的是各个线程内部相互等待的关系;

CyclicBarrier能够处理更复杂的场景,如果计算发生错误,可以重置计数器让线程重新执行一次;

CyclicBarrier中提供了很多有用的方法,比如:可以通过getNumberWaiting()方法获取阻塞的线程数量,通过isBroken()方法判断阻塞的线程是否被中断;

代码示例

示例代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class CyclicBarrierExample {
  private static CyclicBarrier cyclicBarrier = new CyclicBarrier(5);
  public static void main(String[] args) throws Exception {
    ExecutorService executorService = Executors.newCachedThreadPool();
    for (int i = 0; i < 10; i++){
      final int threadNum = i;
      Thread.sleep(1000);
      executorService.execute(() -> {
        try {
          race(threadNum);
       } catch (Exception e) {
          e.printStackTrace();
       }
     });
   }
executorService.shutdown();
 }
  private static void race(int threadNum) throws Exception{
    Thread.sleep(1000);
    log.info("{} is ready", threadNum);
    cyclicBarrier.await();
    log.info("{} continue", threadNum);
 }
}

设置等待超时示例代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class CyclicBarrierExample {
  private static CyclicBarrier cyclicBarrier = new CyclicBarrier(5);
  public static void main(String[] args) throws Exception {
    ExecutorService executorService = Executors.newCachedThreadPool();
    for (int i = 0; i < 10; i++){
      final int threadNum = i;
      Thread.sleep(1000);
      executorService.execute(() -> {
        try {
          race(threadNum);
       } catch (Exception e) {
          e.printStackTrace();
       }
     });
   }
    executorService.shutdown();
 }
  private static void race(int threadNum) throws Exception{
    Thread.sleep(1000);
    log.info("{} is ready", threadNum);
    try{
      cyclicBarrier.await(2000, TimeUnit.MILLISECONDS);
   }catch (BrokenBarrierException | TimeoutException e){
      log.warn("BarrierException", e);
   }
    log.info("{} continue", threadNum);
 }
}

在声明CyclicBarrier的时候,还可以指定一个Runnable,当线程达到屏障的时候,可以优先执行Runnable中的方法。示例代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class CyclicBarrierExample {
  private static CyclicBarrier cyclicBarrier = new CyclicBarrier(5, () -> {
    log.info("callback is running");
 });
  public static void main(String[] args) throws Exception {
    ExecutorService executorService = Executors.newCachedThreadPool();
    for (int i = 0; i < 10; i++){
      final int threadNum = i;
      Thread.sleep(1000);
      executorService.execute(() -> {
        try {
          race(threadNum);
       } catch (Exception e) {
          e.printStackTrace();
       }
     });
   }
    executorService.shutdown();
 }
  private static void race(int threadNum) throws Exception{
    Thread.sleep(1000);
    log.info("{} is ready", threadNum);
    cyclicBarrier.await();
    log.info("{} continue", threadNum);
 }
}

cyclicBarrier实现原理

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private final ReentrantLock lock = new ReentrantLock();
private final Condition trip = lock.newCondition();
//表示处在等待状态的线程个数
private int count;
//构造函数
public CyclicBarrier(int parties, Runnable barrierAction) {
  if (parties <= 0) throw new IllegalArgumentException();
    this.parties = parties;
    this.count = parties;
    this.barrierCommand = barrierAction;
}

CyclicBarrier主要借助重入锁ReentrantLock和Condition实现,count初始值等于CyclicBarrier实例化指明的等待线程数量,用于等待线程计数,parties表示有多少个个体(相当于调多少次await方法,每调一次await方法相当于一个线程到达了栅栏处),barrierAction其实相当于回调函数,当最后一个线程达到了栅栏处就会触发这个回调函数;

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-08-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 对线JAVA面试 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
SpringCloud Stream消息驱动代码实战
cloud-stream-rabbitmq-provider8801, 作为生产者进行发消息模块
一个风轻云淡
2022/11/13
2370
SpringCloud Stream消息驱动代码实战
10SpringCloud Stream消息驱动
原因:rabbitmq从3.3.0开始禁止使用guest/guest权限通过除localhost外的访问
Remember_Ray
2020/11/04
3490
10SpringCloud Stream消息驱动
SpringCloud Stream消息驱动
cheese
2023/10/25
3470
SpringCloud Stream消息驱动
SpringCloud集成Stream
有没有一种新的技术诞生,让我们不再关注具体MQ的细节,我们只需要用一种适配绑定的方式,自动的给我们在各种MQ内切换。(类似于Hibernate)
大忽悠爱学习
2021/12/08
5010
SpringCloud集成Stream
Stream 消息驱动
有没有一种新的技术诞生,让我们不再关注具体MQ的细节,我们只需要用一种适配绑定的方式,自动的给我们在各种MQ内切换。(类似于Hibernate)
用户9615083
2022/12/25
4200
Stream 消息驱动
SpringCloud之Stream
比方说我们用到了RabbitMQ和Kafka,由于这两个消息中间件的架构上的不同,像RabbitMQ有exchange,kafka有Topic和Partitions分区。
shaoshaossm
2022/12/27
3780
SpringCloud之Stream
SpringCloud Stream消息驱动
  官方定义 Spring Cloud Stream 是一个构建消息驱动微服务的框架。应用程序通过 inputs 或者 outputs 来与 Spring Cloud Stream中binder对象交互。通过我们配置来binding(绑定) ,而 Spring Cloud Stream 的 binder对象负责与消息中间件交互。
别团等shy哥发育
2023/02/25
4390
SpringCloud Stream消息驱动
15-SpringCloud Stream
应用程序通过inputs或者 outputs 来与Spring Cloud Stream中binder对象交互。
彼岸舞
2021/09/09
5570
15-SpringCloud Stream
SpringCloud Stream消息驱动
目前市面上常用的四种消息中间件:ActiveMQ、RabbitMQ、RocketMQ、Kafka。由于每个项目需求的不同,在消息中间件的选型上也就会不同。
乐心湖
2021/01/18
8950
SpringCloud Stream消息驱动
springcloud : Stream消息驱动
官网 : https://spring.io/projects/spring-cloud-stream#overview
冷环渊
2021/10/19
6870
消息驱动(SpringCloud Stream)
官网:https://spring.io/projects/spring-cloud-stream#overview https://cloud.spring.io/spring-cloud-static/spring-cloud-stream/3.0.1.RELEASE/reference/html/ Spring Cloud Stream中文指导手册: https://m.wang1314.com/doc/webapp/topic/20971999.html
鱼找水需要时间
2023/02/16
4390
消息驱动(SpringCloud Stream)
微服务(十二)——Steam消息驱动&Sleuth链路监控
有没有一种新的技术诞生,让我们不再关注具体MQ的细节,我们只需要用一种适配绑定的方式,自动的给我们在各种MQ内切换。(类似于Hibernate)
不愿意做鱼的小鲸鱼
2022/09/26
4700
微服务(十二)——Steam消息驱动&Sleuth链路监控
springCloud --- 中级篇(3)
本系列笔记涉及到的代码在GitHub上,地址:https://github.com/zsllsz/cloud
贪挽懒月
2020/06/08
8330
springCloud --- 中级篇(3)
springcloud之Stream
创建项目cloud-stream-rabbitmq-consumer8803与cloud-stream-rabbitmq-consumer8802是并列的消费者。 此时生产者发送消息,这两个消费者都会收到,因为默认情况下不同的微服务是不同组,是并列关系,只要改为竞争关系即可。
Java微观世界
2025/01/20
910
springcloud之Stream
Spring Cloud 学习笔记(2 / 3)
1:N除了个别重要核心业务有专属,其它普通的可以通过@DefaultProperties(defaultFallback = “”)统一跳转到统一处理结果页面
全栈程序员站长
2022/09/05
2K0
Spring Cloud 学习笔记(2 / 3)
SpringCloud - 待整理
1.cloud-provider-payment8001微服务提供者支付Module模块
郭顺发
2021/12/17
7250
springCloud - 第4篇 - 消费者调用服务 ( Feign )
2. spring Initializr - module SDK 选择自己的 JDK ,其余的可以不用填写,next。
微风-- 轻许--
2019/08/01
5370
SpringCloud Bus 消息总线
​ 分布式自动刷新配置功能,Spring Cloud Bus 配合 Spring Cloud Config 使用可以实现配置的动 态刷新。
OY
2022/03/17
5690
SpringCloud Bus 消息总线
Spring cloud stream【消息分组】
  上篇文章我们简单的介绍了stream的使用,发现使用还是蛮方便的,但是在上个案例中,如果有多个消息接收者,那么消息生产者发送的消息会被多个消费者都接收到,这种情况在某些实际场景下是有很大问题的,比如在如下场景中,订单系统我们做集群部署,都会从RabbitMQ中获取订单信息,那如果一个订单同时被两个服务获取到,那么就会造成数据错误,我们得避免这种情况。这时我们就可以使用Stream中的消息分组来解决了!
用户4919348
2019/07/03
1.2K0
Spring cloud stream【消息分组】
springCloud - 第3篇 - 消费者调用服务 ( RestTemplate + Ribbon )
2. spring Initializr - module SDK 选择自己的 JDK ,其余的可以不用填写,next。
微风-- 轻许--
2019/08/01
7270
相关推荐
SpringCloud Stream消息驱动代码实战
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验