CyclicBarrier与CountDownLatch使用

本文详细介绍了并发工具类CyclicBarrier与CountDownLatch的区别与应用场景。通过具体代码示例展示了如何利用这两种工具来同步线程,实现带有阶段性的操作或确保某些任务在其他任务完成后执行。

首先查看CyclicBarrier的类图

 

发现CyclicBarrier并没有超类和实现接口,因此CyclicBarrier只是一个工具类,用以协调线程运行;

与之类似 CountDownLatch也是一个工具类,下面列举了其主要方法

至于两者,对CyclicBarrier比较在意其await方法,而CountDownLatch则比较在意其await与countDown方法

一个简单的小实例:


import java.util.concurrent.*;

public class Main{
    public static void main(String[] args) {
        Runnable runnable=new Runnable() {
            @Override
            public void run() {
                System.out.println("当前5个阶段结束");
            }
        };
        CyclicBarrier barrier=new CyclicBarrier(3,runnable);
        CountDownLatch latch=new CountDownLatch(3);

        for(int i=0;i<3;i++){
            MyThread thread=new MyThread(barrier,latch);
            thread.start();
        }
        try {
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            System.out.println("执行完成");
        }
    }
    static class MyThread extends Thread{
        private final CyclicBarrier barrier;
        private final CountDownLatch latch;
        //当前每个线程均有5个阶段
        private static int PHASE=5;

        MyThread(CyclicBarrier barrier,CountDownLatch latch) {
            this.barrier = barrier;
            this.latch=latch;
        }


        @Override
        public void run() {
            for(int phase=0;phase<PHASE;phase++){
                try {
                    doPhase(phase);
                    barrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }
            latch.countDown();

        }
        protected void doPhase(int phase) throws InterruptedException {
            System.out.println("当前线程"+this.getName()+"正在执行第"+phase+"阶段");
            Thread.sleep(1000);
            System.out.println("当前线程"+this.getName()+"已结束第"+phase+"阶段");
        }
    }
}

输出:

当前线程Thread-0正在执行第0阶段
当前线程Thread-2正在执行第0阶段
当前线程Thread-1正在执行第0阶段
当前线程Thread-0已结束第0阶段
当前线程Thread-1已结束第0阶段
当前线程Thread-2已结束第0阶段
当前5个阶段结束
当前线程Thread-0正在执行第1阶段
当前线程Thread-1正在执行第1阶段
当前线程Thread-2正在执行第1阶段
当前线程Thread-2已结束第1阶段
当前线程Thread-0已结束第1阶段
当前线程Thread-1已结束第1阶段
当前5个阶段结束
当前线程Thread-1正在执行第2阶段
当前线程Thread-0正在执行第2阶段
当前线程Thread-2正在执行第2阶段
当前线程Thread-1已结束第2阶段
当前线程Thread-0已结束第2阶段
当前线程Thread-2已结束第2阶段
当前5个阶段结束
当前线程Thread-2正在执行第3阶段
当前线程Thread-1正在执行第3阶段
当前线程Thread-0正在执行第3阶段
当前线程Thread-0已结束第3阶段
当前线程Thread-1已结束第3阶段
当前线程Thread-2已结束第3阶段
当前5个阶段结束
当前线程Thread-2正在执行第4阶段
当前线程Thread-0正在执行第4阶段
当前线程Thread-1正在执行第4阶段
当前线程Thread-1已结束第4阶段
当前线程Thread-0已结束第4阶段
当前线程Thread-2已结束第4阶段
当前5个阶段结束
执行完成
 

分析:

CyclicBarrier的用途是创建一个栅栏(从其名字中的Barrier可以看出),构造函数为

CyclicBarrier(int parties, Runnable barrierAction)

意思是在线程A调用它(CyclicBarrier)的await方法后,线程A将会阻塞在这里。直到同一个barrier上的线程调用其await方法达到预先构造函数中int值的次数,所有在此处的线程阻塞将会结束,如果barrierAction不为null,在阻塞结束后将调用该barrierAction的run方法。由其名字中的Cyclic可以看出该类是可重用的,当await的阻塞解除后再次调用await将会再次堵塞;

CountDownLatch

称之为闭锁(严格来说这并不是闭锁,只是闭锁的一种实现罢了,但长久以来大家都这么叫了),

其构造函数

CountDownLatch(int count)

说明在某线程调用其await方法后会阻塞,须经其countDown方法调用count次后,阻塞解除,进而继续执行

由于这两者的特性,往往CyclicBarrier常用来实现带有阶段性质的操作或者需要实现某种协议,比如几个家庭决定在6点在麦当劳集合等等,CountDownLatch用以实现确保某些活动知道其他活动都完成后才继续进行,相较两者而言,一些操作使用两者都能实现,因此过于区分两者含义是不正当的;以我而言,两者只存在语义上的差异,功能上一个具有阻塞结束后的操作而另一个没有罢了(实现此操作并不困难);

另外对于InterruptionException这个异常的捕获也很有技巧;

InterruptedException

是一个受检异常,需要显式抛出或者强制处理,当某个方法抛出该异常时,如果你不知道如何处理,请仍旧抛出,如果抛出此异常担心会污染已设计好的接口,请将其装饰为非受检异常(如

IllegalStateException

)再抛出,并给以文档说明;

如下:

try{
    //操作 可能抛出InterruptedException
}catch(InterruptedException e){
    if(knowHowToHandle()){
        handleException();
    }else if(DoWantTointerface()){
        throw new RuntimeException(e);
    }
    else {
        otherOperations();
    }
}
【直流微电网】径向直流微电网的状态空间建模线性化:一种耦合DC-DC变换器状态空间平均模型的方法 (Matlab代码实现)内容概要:本文介绍了径向直流微电网的状态空间建模线性化方法,重点提出了一种基于耦合DC-DC变换器状态空间平均模型的建模策略。该方法通过对系统中多个相互耦合的DC-DC变换器进行统一建模,构建出整个微电网的集中状态空间模型,并在此基础上实施线性化处理,便于后续的小信号分析稳定性研究。文中详细阐述了建模过程中的关键步骤,包括电路拓扑分析、状态变量选取、平均化处理以及雅可比矩阵的推导,最终通过Matlab代码实现模型仿真验证,展示了该方法在动态响应分析和控制器设计中的有效性。; 适合人群:具备电力电子、自动控制理论基础,熟悉Matlab/Simulink仿真工具,从事微电网、新能源系统建模控制研究的研究生、科研人员及工程技术人员。; 使用场景及目标:①掌握直流微电网中多变换器系统的统一建模方法;②理解状态空间平均法在非线性电力电子系统中的应用;③实现系统线性化并用于稳定性分析控制器设计;④通过Matlab代码复现和扩展模型,服务于科研仿真教学实践。; 阅读建议:建议读者结合Matlab代码逐步理解建模流程,重点关注状态变量的选择平均化处理的数学推导,同时可尝试修改系统参数或拓扑结构以加深对模型通用性和适应性的理解。
在Java并发编程中,`CyclicBarrier`和`CountDownLatch`是两个重要的同步工具类,它们都用于协调多个线程的执行,但在设计理念、使用场景以及功能特性上存在显著差异。 ### `CountDownLatch` `CountDownLatch`是一个一次性的同步工具,它允许一个或多个线程等待其他线程完成操作。其核心机制是基于一个计数器,当计数器减到零时,所有因调用`await()`方法而阻塞的线程将被释放[^2]。这个计数器只能初始化一次,并且一旦减少到零,就不能再改变它的值[^4]。 #### 使用场景 - **启动信号**:主线程创建并启动多个工作线程后,可以使用`CountDownLatch`来确保所有的工作线程都准备好开始执行后再一起开始。 - **结束信号**:多个工作线程完成各自的任务之后通知另一个线程进行汇总处理,例如统计结果或者关闭资源等。 ```java public class CountdownLatchExample { public static void main(String[] args) throws InterruptedException { int N = 4; CountDownLatch doneSignal = new CountDownLatch(N); // 创建N个线程 for (int i = 0; i < N; ++i) { new Thread(new WorkerRunnable(doneSignal)).start(); } // 等待所有线程完成 doneSignal.await(); System.out.println("所有线程已完成."); } } class WorkerRunnable implements Runnable { private final CountDownLatch doneSignal; WorkerRunnable(CountDownLatch doneSignal) { this.doneSignal = doneSignal; } public void run() { try { doWork(); doneSignal.countDown(); } catch (InterruptedException ex) {} } void doWork() { /* 执行具体任务 */ } } ``` ### `CyclicBarrier` `CountDownLatch`不同的是,`CyclicBarrier`设计为可重用的屏障点,它可以重复使用多次。一组线程到达屏障时会被阻塞,直到最后一个线程也到达了屏障点,这时所有的线程才会被释放继续执行。此外,还可以选择性地提供一个`Runnable`作为屏障动作,在所有线程释放前执行一次[^1]。 #### 使用场景 - **并行迭代计算**:比如在进行某些数学运算时,每个阶段需要所有参线程完成当前阶段的工作后才能进入下一阶段。 - **游戏准备就绪**:在线游戏中玩家需要等待其他玩家加载完毕后才开始游戏。 ```java public class CyclicBarrierExample { public static void main(String[] args) { int parties = 3; CyclicBarrier barrier = new CyclicBarrier(parties, () -> System.out.println("所有参者已就位,准备行动!")); for(int i=0; i<parties; i++) { new Thread(new Task(barrier)).start(); } } } class Task implements Runnable{ private CyclicBarrier barrier; public Task(CyclicBarrier barrier) { this.barrier = barrier; } @Override public void run() { try { System.out.println(Thread.currentThread().getName() + " 正在准备..."); Thread.sleep((long)(Math.random()*5000)); System.out.println(Thread.currentThread().getName() + " 准备好了,等待其他成员..."); barrier.await(); System.out.println(Thread.currentThread().getName() + " 开始行动!"); } catch (Exception e) { e.printStackTrace(); } } } ``` ### 区别总结 - **生命周期**:`CountDownLatch`是一次性的,而`CyclicBarrier`可以在每次屏障被突破后通过调用`reset()`方法重新初始化以供再次使用。 - **控制方向**:`CountDownLatch`通常由一个线程(通常是主线程)用来等待其他线程完成;而`CyclicBarrier`则是由一组线程相互等待对方到达屏障点。 - **异常处理**:如果某个线程在等待`CyclicBarrier`时被打断,则整个屏障会被破坏,导致其他线程抛出`BrokenBarrierException`;而对于`CountDownLatch`来说,中断不会影响其他线程的状态。 综上所述,根据实际需求选择合适的同步工具是非常关键的。如果需要实现简单的“等待直到某事件发生”的逻辑,那么`CountDownLatch`可能是更好的选择;而对于那些要求多个阶段同步且可能需要反复使用的场合,则更适合采用`CyclicBarrier`。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值