java并发-CyclicBarrier使用

2023-12-16 05:39:41


它是 Java 中用于多线程同步的一个工具类,它允许一组线程互相等待,直到所有线程都达到某个屏障点(barrier),然后再同时执行。

基本使用

  1. 创建对象: 使用构造函数创建一个 CyclicBarrier 对象,需要指定参与同步的线程数量和达到屏障点时要执行的任务。
CyclicBarrier barrier = new CyclicBarrier(parties, barrierAction);
  • parties:指定参与同步的线程数量。
  • barrierAction:可选的任务,当所有线程都到达屏障点时执行。
  1. 线程等待: 在需要同步的线程中调用 await() 方法,表示线程已经到达屏障点。线程将被阻塞,直到所有线程都到达屏障点。
try {
    barrier.await();
} catch (InterruptedException | BrokenBarrierException e) {
    // 处理异常
}
  1. 屏障点任务: 当所有线程都到达屏障点时,可以执行指定的任务(如果有的话)。
CyclicBarrier barrier = new CyclicBarrier(3, () -> {
    // 当所有线程都到达屏障点时执行的任务
    System.out.println("Barrier reached, all threads are here!");
});
  1. 重用: CyclicBarrier 可以被重用,一旦所有线程到达屏障点并执行了屏障点任务,CyclicBarrier就会被重置,可以再次使用。
barrier.reset();
  1. 异常处理: 当等待的线程被中断或者在等待过程中发生异常,可以捕获 InterruptedExceptionBrokenBarrierException 进行处理。
try {
    barrier.await();
} catch (InterruptedException | BrokenBarrierException e) {
    // 处理异常
}

使用场景

假设有一个多线程程序,其中有三个线程分别执行不同的任务,而在某一点需要等待所有线程都完成自己的任务后再一起执行下一步操作,你可以使用 CyclicBarrier 来实现这个同步点。例如:

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

class Worker implements Runnable {
    private final CyclicBarrier barrier;
    private final String name;

    public Worker(CyclicBarrier barrier, String name) {
        this.barrier = barrier;
        this.name = name;
    }

    @Override
    public void run() {
        System.out.println(name + " is working...");
        try {
            // 模拟工作耗时
            Thread.sleep((long) (Math.random() * 2000));
            System.out.println(name + " has finished its work and is waiting at the barrier.");
            
            // 等待其他线程到达屏障点
            barrier.await();
            
            System.out.println(name + " continues its work after the barrier.");
        } catch (InterruptedException | BrokenBarrierException e) {
            e.printStackTrace();
        }
    }
}

public class CyclicBarrierExample {
    public static void main(String[] args) {
        int numberOfThreads = 3;
        CyclicBarrier barrier = new CyclicBarrier(numberOfThreads, () -> {
            System.out.println("All threads have reached the barrier. Let's move on!");
        });

        // 创建并启动多个线程
        for (int i = 1; i <= numberOfThreads; i++) {
            Thread workerThread = new Thread(new Worker(barrier, "Thread " + i));
            workerThread.start();
        }
    }
}

运行结果:

Thread 1 is working...
Thread 2 is working...
Thread 3 is working...
Thread 1 has finished its work and is waiting at the barrier.
Thread 3 has finished its work and is waiting at the barrier.
Thread 2 has finished its work and is waiting at the barrier.
All threads have reached the barrier. Let's move on!
Thread 1 continues its work after the barrier.
Thread 3 continues its work after the barrier.
Thread 2 continues its work after the barrier.

基本的执行流程应该如下:

  1. 每个线程会打印一条消息表示它正在工作。
  2. 然后,每个线程会模拟执行一些工作,即线程睡眠一段随机时间。
  3. 完成工作后,线程会打印一条消息表示它已经完成工作,并等待在屏障点。
  4. 当所有线程都到达屏障点后,屏障点任务会执行,打印一条消息表示所有线程都已经到达屏障点。
  5. 所有线程将继续执行下一步操作。

常用方法解释

  1. **CyclicBarrier(int parties)**
  • 通过指定参与同步的线程数量来创建 CyclicBarrier 对象。
  1. **CyclicBarrier(int parties, Runnable barrierAction)**
  • 通过指定参与同步的线程数量和达到屏障点时要执行的任务来创建 CyclicBarrier 对象。
  1. **int await()**
  • 使当前线程在屏障点等待,直到所有线程都到达屏障点。
  • 返回当前线程在屏障点的索引,范围从0到参与同步的线程数量减1。
  1. **int await(long timeout, TimeUnit unit)**
  • 类似于 await() 方法,但是允许设置等待的最大时间。
  • 返回当前线程在屏障点的索引,或者如果在指定的时间内未到达屏障点,则返回负值。
  1. **int getParties()**
  • 返回参与同步的线程数量。
  1. **int getNumberWaiting()**
  • 返回当前等待在屏障点的线程数量。
  1. **boolean isBroken()**
  • 判断屏障点是否被中断。
  • 如果有一个或多个线程由于等待在屏障点时被中断,则返回 true
  1. **void reset()**
  • 重置屏障点,使其恢复到初始状态。
  • 如果有线程正在等待在屏障点,则它们将抛出 BrokenBarrierException 异常。

CyclicBarrier 和 CountDownLatch 的异同

  • 作用对象不同

    CountDownLatch 作用于事件,但 CyclicBarrier 作用于线程;CountDownLatch 是在调用了 countDown 方法之后把数字倒数减 1而 CyclicBarrier 是在某线程开始等待后把计数减 1。
    
  • 可重用性不同

CountDownLatch 在倒数到 0 并且触发门闩打开后,就不能再次使用了,除非新 建一个新的实例;CyclicBarrier 可以重复使用CyclicBarrier 还可以随时调用 reset 方法进行重置,如果 重置时有线程已经调用了 await 方法并开始等待,那么这些线程则会抛出BrokenBarrierException异常。

  • 执行动作不同

CyclicBarrier 有执行动作 barrierAction,而 CountDownLatch 没这个功能。

文章来源:https://blog.csdn.net/qq_36649893/article/details/135027061
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。