首页 > 编程语言 >Java 入门指南:Java 并发编程 —— 同步工具类 CyclicBarrier(循环屏障)

Java 入门指南:Java 并发编程 —— 同步工具类 CyclicBarrier(循环屏障)

时间:2024-09-11 22:20:45浏览次数:11  
标签:await Java 登山者 编程 屏障 线程 CyclicBarrier 等待

文章目录

同步工具类

JUC(Java.util.concurrent)是 Java 提供的用于并发编程的工具类库,其中包含了一些通信工具类,用于在多个线程之间进行协调和通信,特别是在多线程和网络通信方面。这些工具类提供了丰富的功能,帮助开发者高效地实现复杂的并发控制和网络通信需求。

![[JUC Communication Utilities.png]]

CyclicBarrier

CyclicBarrier(循环屏障)是 Java 中的一种同步辅助类,用于控制多个线程在某个屏障点上等待,然后在达到屏障点时一起继续执行。它允许一组线程互相等待,直到所有线程都达到某个公共屏障点(也称为同步点),然后这些线程才会一起继续执行后续的任务。与 CountDownLatch 类似,但可以重复使用

CyclicBarrier 通过一个计数器来实现,计数器初始值可以设定为一个正整数,当调用 await() 方法的线程数量达到指定值时,所有线程会被释放并继续执行。同时,CyclicBarrier 的计数器会重置为初始值,以便下一轮的等待。

构造函数

CyclicBarrier 提供了两个构造函数:

  1. 创建一个新的 CyclicBarrier,它将等待给定数量的线程(即 parties 参数指定的数量)到达屏障点,然后这些线程才会继续执行。
CyclicBarrier(int parties)
  1. 另一个构造函数除了指定需要等待的线程数量外,还允许指定一个当所有线程都到达屏障点时执行的任务(即barrierAction)。这个任务在所有线程被释放之前执行,可以用于进行某些准备工作或汇总工作。
CyclicBarrier(int parties, Runnable barrierAction)

常用方法

  • await():这是主要的等待方法,当所有线程都调用此方法时,所有线程都会被释放继续执行。该方法有两个重载版本:

    • await():等待所有线程,没有超时限制。
    • await(long timeout, TimeUnit unit):等待所有线程,有超时限制。
  • getParties():返回设置屏障时指定的线程数。

  • isBroken():如果屏障因为中断或超时而失效,则返回 true

  • reset():重置屏障,使其可以再次使用。

  • awaitingThreadCount():返回当前正在等待屏障的线程数。

工作机制

  1. 线程阻塞:当线程调用 CyclicBarrierawait() 方法时,如果未达到屏障点(即未达到指定的线程数量),则该线程将被阻塞,直到所有线程都调用 await() 方法并到达屏障点。

  2. 计数器减一:每当一个线程调用 await() 方法时,CyclicBarrier 内部的计数器会减一。当计数器减至零时,表示所有线程都已到达屏障点。

  3. 执行屏障任务(可选):如果构造函数中指定了屏障任务(barrierAction),则在所有线程都到达屏障点后,该任务将被执行。

  4. 线程唤醒:执行完屏障任务(如果有的话)后,所有在屏障点等待的线程都将被唤醒,并继续执行后续的任务。

  5. 重置计数器:在释放所有线程后,CyclicBarrier 的计数器可以被重置,以便下一次使用。如果需要重置计数器,可以调用 reset() 方法。

使用步骤

使用 CyclicBarrier 的基本步骤如下:

  1. 创建一个 CyclicBarrier 对象,并指定参与线程的数量。

  2. 在每个参与线程中,调用 await() 方法,表示线程到达屏障点,等待其他线程到达。

  3. 当指定数量的线程都调用了 await() 方法后,所有线程会被释放,可以继续执行后续操作。

CyclicBarrier 非常灵活,并且可以自定义屏障动作,可以在所有线程到达屏障点触发之前或之后执行一些特定的操作。

CyclicBarrier参与线程数量必须大于等于 2,否则无论怎样调用await() 方法,都会导致线程阻塞。另外,CyclicBarrier 是一次性的,但一旦所有线程被释放,计数器会重置为初始值,可以进行下一轮的等待。

CyclicBarrier 在多线程协调和同步的场景中非常有用,可以控制线程的执行顺序和等待状态,提高并发性能和效率。

适用场景

CyclicBarrier 的使用场景通常是多个线程需要相互等待,直到所有线程都到达某个屏障点,然后再一起开始执行后续操作。常见的应用场景有:

  1. 将一个大任务拆分成多个子任务,多个线程并发执行这些子任务,最后等待所有子任务完成后再汇总结果。

  2. 执行多个并发测试用例,所有测试用例需要同时开始执行,在一个屏障点等待并打开屏障,然后进行下一次测试。

CyclicBarrier与CountDownLatch的区别

虽然 CyclicBarrierCountDownLatch(倒计时门闩) 都可以用来实现线程间的同步,但它们之间存在一些关键的区别:

  1. 计数器重置CountDownLatch 的计数器只能使用一次,一旦计数器减为零,就不能再被重置。而 CyclicBarrier 的计数器可以通过调用reset()方法来重置,以便重复使用。

  2. 使用场景CountDownLatch 主要用于一组线程等待另一组线程完成某项操作,而 CyclicBarrier 则主要用于一组线程互相等待,直到所有线程都达到某个同步点后再一起继续执行。

  3. 异常处理:当 CyclicBarrier 的屏障被破坏时(例如,由于某个线程在等待时被中断或超时),它会抛出 BrokenBarrierException 异常。而 CountDownLatch 则没有类似的异常处理机制。

示例代码

让我们通过一个具体的例子来展示 CyclicBarrier 的使用。

我们将模拟一个场景:一群登山者计划一起出发去攀登一座山。但是,他们约定在一个集合点汇合,只有当所有人都到齐了,他们才会开始攀登。如果有人提前到达,他们会等待其他人。如果有登山者因为某种原因无法到达集合点(如被中断或超时未到),那么整个队伍的计划就会取消。

import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ClimbersExample {

    public static void main(String[] args) throws InterruptedException {
        int numberOfClimbers = 5;
        CyclicBarrier barrier = new CyclicBarrier(numberOfClimbers, () -> {
            System.out.println("所有登山者已经集合完毕,开始攀登!");
        });

        ExecutorService executor = Executors.newFixedThreadPool(numberOfClimbers);

        for (int i = 0; i < numberOfClimbers; i++) {
            final int climberNumber = i + 1;
            executor.submit(() -> {
                try {
                    System.out.println("登山者 " + climberNumber + " 正在前往集合点...");
                    Thread.sleep((long) (Math.random() * 5000)); // 模拟不同的准备时间
                    System.out.println("登山者 " + climberNumber + " 到达集合点");
                    barrier.await(); // 等待所有登山者
                } catch (InterruptedException | BrokenBarrierException e) {
                    System.err.println("登山者 " + climberNumber + " 无法到达集合点: " + e.getMessage());
                }
            });
        }

        executor.shutdown();
    }
}

示例说明:

  1. 初始化 CyclicBarrier:我们创建了一个 CyclicBarrier,指定了参与的登山者数量为5,并且当所有登山者都到达集合点时,会执行一个 Runnable 任务,输出信息表示登山活动可以开始。

  2. 创建线程池:我们创建了一个固定大小的线程池来模拟5位登山者的行动。

  3. 提交任务:每个登山者都有自己的任务,模拟他们准备的时间不同,到达集合点的时间也不同。

  4. 等待所有登山者:每个登山者到达集合点后,会调用 barrier.await() 方法,等待其他登山者。只有当所有登山者都到达集合点后,才会继续执行后续的操作。

  5. 处理异常:如果某个登山者被中断或者因为其他原因无法到达集合点,会捕获异常并打印相关信息。

  6. 关闭线程池:最后,我们关闭线程池,确保资源得到释放。

标签:await,Java,登山者,编程,屏障,线程,CyclicBarrier,等待
From: https://blog.csdn.net/Zachyy/article/details/142151648

相关文章

  • Java面试八股文
    目录Java基础1、Hashmap底层原理2、如何解决哈希冲突2.1你知道HahsMap死循环问题吗?3、Concurrenthashmap为什么是线程安全的?TreeMap,HashMap,LinkedHashMap的区别?4、super和this的共同点的区别5、final关键字6、集合6.1、map6.2、set6.3List6.4、Queu6.5、Sta......
  • 在线编程实现!如何在Java后端通过DockerClient操作Docker生成python环境
    目录在线编程实现!如何在Java后端通过DockerClient操作Docker生成python环境一、为什么要用后端程序操作Docker二、安装Docker1、安装Docker2、启动Docker三、DockerClient与CMD操作Docker的区别四、干货!如何使用DockerClient实现在线编程1、前置工作①引入并安装依赖......
  • Javaweb之SpringBootWeb案例文件上传的详细解析
     2.文件上传在我们完成的新增员工功能中,还存在一个问题:没有头像(图片缺失)编辑上述问题,需要我们通过文件上传技术来解决。下面我们就进入到文件上传技术的学习。文件上传技术这块我们主要讲解三个方面:首先我们先对文件上传做一个整体的介绍,接着再学习文件上传的本地存储方式,最后......
  • JAVA入门程序
    javajava发展史JavaSE(JavaPlatform,StandardEdition标准版):允许您在桌面和服务器上开发和部署Java应用程序JavaEE(JavaPlatform,EnterpriseEdition企业版):是为开发企业环境下的应用程序提供的一套解决方案,主要针对于Web应用程序开发(页面+服务器)JavaME(JavaPlat......
  • 【快速解决】Maven安装和配置详细教程,解决你可能出现的问题Error: JAVA_HOME not foun
    看着文章一步一步来......
  • JAVA运维总结篇
    写这篇文章主要目的是完成自己多年来运维JAVA应用的一个总结,相当于个人知识库,以后工作中遇到问题便于临时查阅并不断完善自己的知识体系。 Tomcat是一个开箱即用的软件,配置java环境变量即可把Tomcat进程运行起来,但要投入生产环境,有哪些需要注意的呢?(1)、性能,默认的Tomcat配置可以正......
  • Java:类和对象(2)
    一对象的构建和初始化1.对象构建(ObjectConstruction)Studentstudent1=newStudent("zhangsan",12,"123456");Studentstudent2=newStudent("lisi",10,"15236");2.构造函数(Constructor)构造函数的特性:名字与类名相同。没有返回类型。可以重载(多个构造函数可以具有不......
  • 网络编程day05(循环服务器、并发服务器)
    目录服务器模型 1》循环服务器 2》并发服务器1>多进程:每有一个客户端连接创建一个进程进行通信2> 多线程:每有一个客户端连接创建一个线程进行通信 3>IO多路复用4>总结服务器模型在网络通信中,通常一个服务器要连接多个客户端为了处理多个客户端的请求,通常......
  • Java——多态
    什么是多态:        多态的概念:通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状态。可能不太懂是什么意思,那首先来简单实现一个:(看效果!!)     classAnamals{Stringname;Stringcolor;public......
  • Day07.Java方法
    Java方法方法的定义和调用Java方法是语句的集合,它们在一起执行一个功能方法是解决一类问题的步骤的有序组合方法包含于类或对象中方法在程序中被创建,在其他地方被引用设计方法的原则:方法的本意是功能块,就是实现某个功能的语句块的集合。我们设计方法的时候,最好保持方法的......