Java中的 CyclicBarrier详解

Java中的 CyclicBarrier详解

1. 什么是CyclicBarrier

CyclicBarrier是Java并发包中的一个类,可以让一组线程在某个条件达成时全部同时开始执行。简而言之,CyclicBarrier是一种同步机制,它允许指定的线程等待彼此到达某个同步点。

CyclicBarrier和CountDownLatch都可以用于线程间的同步,但它们之间也存在一些区别。CountDownLatch是一种能够使一个或多个线程等待一系列指定的任务执行完后再执行的同步机制,而CyclicBarrier是一种等待所有线程都满足某个条件后再继续执行的同步机制。

CyclicBarrier的用法非常简单,只需要在创建实例时指定同步点即可,线程在运行过程中到达同步点时将被阻塞,直到所有线程都到达同步点后才会一起继续执行。

2. CyclicBarrier常用方法

CyclicBarrier类提供了一些方法可以用于实现线程间的同步控制。

2.1 构造方法

CyclicBarrier的构造方法有两种基本形式:

public CyclicBarrier(int parties)

构造一个新的CyclicBarrier,它将在指定数量的线程(称为parties)等待之后启动执行。

public CyclicBarrier(int parties, Runnable barrierAction)

构造一个新的CyclicBarrier,它将在指定数量的线程等待之后启动执行,并会执行指定的Runnable。

2.2 await()

CyclicBarrier的唯一方法是await(),调用await()表示该线程已经到达了同步点。当某个线程调用await()时,它将会被阻塞,而其他线程继续执行,直到所有线程都到达了同步点。

public void await() throws InterruptedException, BrokenBarrierException;

2.3 reset()

CyclicBarrier还提供了reset()方法,用于重置同步点。在调用reset()方法后,所有已经在等待的线程都将抛出BrokenBarrierException异常。

public void reset();

3. CyclicBarrier的使用示例

下面的示例演示了如何使用CyclicBarrier来实现一批线程同时开始执行:


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

public class CyclicBarrierDemo {
    public static void main(String[] args) {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(5, new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + " is working");
            }
        });

        for (int i = 0; i < 5; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName() + " is waiting");
                    try {
                        cyclicBarrier.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + " is working");
                }
            }, "Thread-" + i).start();
        }
    }
}

运行结果如下:

Thread-2 is waiting
Thread-3 is waiting
Thread-4 is waiting
Thread-0 is waiting
Thread-1 is waiting
Thread-2 is working
Thread-3 is working
Thread-4 is working
Thread-0 is working
Thread-1 is working

上面的代码中,我们创建了一个CyclicBarrier实例,其参数parties为5,表示要等待5个任务完成。在每一个线程中,我们先打印出当前线程正在等待,然后调用cyclicBarrier.await()方法将线程阻塞。当所有线程都到达了同步点后,会执行CyclicBarrier的构造方法中指定的Runnable,同时所有被阻塞的线程开始同步执行,打印出"Thread-x is working",x为线程的编号。

另一个示例演示了如何使用CyclicBarrier来模拟比赛的开始、进行和结束,其中比赛有三个阶段:准备、开始、结束。


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

public class RaceDemo {
    private static CyclicBarrier cyclicBarrier;

    public static void main(String[] args) throws InterruptedException {
        cyclicBarrier = new CyclicBarrier(4, new Runnable() {
            @Override
            public void run() {
                System.out.println("All the players are ready, let's start the game!");
            }
        });

        Player player1 = new Player("Tom");
        Player player2 = new Player("Jerry");
        Player player3 = new Player("Mike");
        Player player4 = new Player("John");

        player1.start();
        player2.start();
        player3.start();
        player4.start();

        player1.join();
        player2.join();
        player3.join();
        player4.join();
    }

    static class Player extends Thread {
        private String name;

        public Player(String name) {
            this.name = name;
        }

        @Override
        public void run() {
            try {
                System.out.println(name + " is preparing...");
                Thread.sleep(1000);
                cyclicBarrier.await();
                System.out.println(name + " starts running...");
                Thread.sleep(3000);
                cyclicBarrier.await();
                System.out.println(name + " is close to the finish line...");
                Thread.sleep(2000);
                cyclicBarrier.await();
                System.out.println(name + " crosses the finish line!");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        }
    }
}

运行结果如下:

Tom is preparing...
Jerry is preparing...
Mike is preparing...
John is preparing...
All the players are ready, let's start the game!
Tom starts running...
Mike starts running...
Jerry starts running...
John starts running...
Jerry is close to the finish line...
Mike is close to the finish line...
Tom is close to the finish line...
John is close to the finish line...
Jerry crosses the finish line!
Mike crosses the finish line!
Tom crosses the finish line!
John crosses the finish line!

上面的代码中,我们创建了一个CyclicBarrier实例,其参数parties为4,表示等待4个运动员准备就绪后开始比赛。在每一个运动员中,我们通过cyclicBarrier.await()将每一个运动员线程阻塞,直到所有运动员都到达同步点。当所有运动员都准备就绪后,CyclicBarrier的构造方法中指定的Runnable开始执行,打印出"All the players are ready, let's start the game!",同时所有阻塞的线程开始继续执行比赛流程。当每一阶段都完成后,所有线程再次被阻塞,等待其他线程完成当前阶段。最后一阶段完成后,所有线程将一起结束比赛。

通过这两个示例,我们可以看到CyclicBarrier的强大功能和使用方法,它可以方便地实现线程之间的同步控制,很好地提高了并发编程的效率。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java中的 CyclicBarrier详解 - Python技术站

(0)
上一篇 2023年5月26日
下一篇 2023年5月26日

相关文章

  • JSP中表达式的使用详解

    《JSP中表达式的使用详解》攻略 一、JSP表达式的介绍 JSP表达式一般用于将变量、常量、函数等的值输出到页面上。 语法格式: <%= 表达式 %> 其中,等号和百分号之间不要有空格。 二、表达式中可使用的内容 变量和常量 在表达式中可以使用变量或常量的值,如: <%= name %> <%= 1234 %> 表达式运算…

    Java 2023年6月15日
    00
  • Hibernate中获取Session的两种方式代码示例

    获取 Hibernate 中的 Session 可以通过两种方式:getCurrentSession() 和 openSession()。 getCurrentSession() 方法 getCurrentSession() 方法获取的 Session 是与当前线程绑定的,使用完后会自动关闭。 示例代码如下: Session session = sessio…

    Java 2023年5月31日
    00
  • java生成图片验证码功能

    下面是详细讲解”Java生成图片验证码功能”的完整攻略: 1. 确定需求 首先,我们需要明确这个功能的需求,即在Java Web应用中生成一个随机的图片验证码,以用于用户填写和校验,防止机器人攻击或恶意提交。 2. 添加依赖 接下来,我们需要添加相关的依赖。Java中生成图片验证码需要用到jcaptcha这个开源工具包,我们可以在pom.xml中添加它的依赖…

    Java 2023年6月15日
    00
  • SpringBoot项目运行jar包启动的步骤流程解析

    下面是关于SpringBoot项目运行jar包启动的步骤流程解析的完整攻略。 1. 编写SpringBoot应用程序 首先,我们需要编写一个SpringBoot应用程序。这里以一个简单的Hello World程序为例: @RestController public class HelloController { @GetMapping("/hell…

    Java 2023年5月19日
    00
  • MySql修改数据库编码为UTF8避免造成乱码问题

    以下是MySql修改数据库编码为UTF8的攻略,具体步骤如下: 步骤一:备份数据库 在进行数据库编码修改之前,为了防止意外情况导致数据丢失,应该先备份好原有的数据库。备份有多种方法,常见的有使用phpMyAdmin或通过mysqldump命令备份。 示例一:使用phpMyAdmin备份数据库 打开phpMyAdmin,选择要备份的数据库。 点击“导出”选项卡…

    Java 2023年5月20日
    00
  • 基于Java写minio客户端实现上传下载文件

    下面是基于Java写minio客户端实现上传下载文件的完整攻略。 1. 安装Minio服务器 首先,需要在本地或服务器上安装Minio服务器,具体步骤可以参考官方文档进行操作。一般来说,可以通过以下命令安装: $ wget https://dl.min.io/server/minio/release/linux-amd64/minio $ chmod +x …

    Java 2023年5月19日
    00
  • 解决java转义json出现\u0000 等乱码的问题

    解决Java转义JSON出现乱码的问题,在于正确地处理JSON字符串的Unicode字符编码方式和转义符。 问题分析 当我们使用Java将一个对象转化为JSON字符串时,如果对象中包含了Unicode字符,经过转义后在JSON字符串中就会出现”\uXXXX”的形式,其中XXXX是Unicode字符的十六进制编码。 然而,在有些情况下,这种转义是会导致乱码的。…

    Java 2023年5月20日
    00
  • Linux下Tomcat8如何修改JVM内存配置

    下面是详细的攻略: 准备工作 在修改Tomcat JVM内存配置之前,需要先确认是否已经安装了JDK。如果尚未安装,请先安装。安装JDK的详细步骤可以参考JDK安装指南。 修改JVM内存配置 打开Tomcat安装目录下的bin文件夹,并找到catalina.sh文件。 打开catalina.sh文件,在文件末尾添加以下代码: JAVA_OPTS=”-Xms5…

    Java 2023年5月20日
    00
合作推广
合作推广
分享本页
返回顶部