【JAVA核心知识】15.2:线程控制器CyclicBarrier

简介​

可重复使用的线程控制器、适用于多个线程需到达某个状态之后再同时开始执行的场景,就好似有道屏障,只有在屏障处等待的线程到指定数量这个屏障才会打开。

常用方法

  • CyclicBarrier(int parties, Runnable barrierAction):构造方法,parties标识要控制的线程数,即当多少个线程在屏障处等待时就放行。barrierAction为需要在放行时同步执行的操作。
  • CyclicBarrier(int parties):构造方法,parties标识要控制的线程数,即当多少个线程在屏障处等待时就放行。
  • int getParties():获得要控制的线程数,即当多少个线程在屏障处等待时就放行。
  • int await():等待屏障处线程达到数量
  • int await(long timeout, TimeUnit unit):等待屏障处线程达到数量 带超时时间
  • boolean isBroken():屏障是否已经被破坏 true为已被破坏
  • void reset():CyclicBarrier可重复使用并不代表屏障每开启一次就要调这个方法一次。每当屏障处到达指定数量的等待线程,屏障会开启并自动关闭等待下一波线程。无需每开启一次就重置一次。这个方法使屏障恢复初始状态,不过如果在重置时有线程在屏障处等待,则抛出BrokenBarrierException.
  • int getNumberWaiting():获得当前在屏障处等待的线程数

示例

package sync;

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

public class CyclicBarrierTest {

    public static void main(String[] args) {
        Runnable allAwaitRun = new Runnable() {
            
            @Override
            public void run() {
                System.out.println("大家都执行完毕了,准备下一步工作喽");
            }
        };
        final CyclicBarrier c = new CyclicBarrier(3, allAwaitRun);  // 参数二为屏障放行之后要启的线程
                                                                    // 如果你实际有3个线程但是屏障设置为2,那么先到的2个会被屏障放行,
                                                                    //最后一个屏障并不知道也不去管,导致最后一个到的一直等待或者超时报TimeoutException
        Runnable r1 = new Runnable() {
            
            @Override
            public void run() {
                System.out.println("线程1开始进行第一步工作...");
                try {
                    Thread.sleep(500); // 等待模式耗时操作
                    System.out.println("线程1第一步工作完毕,进入等待状态...当前等待线程量 - " + c.getNumberWaiting());
                    try {
                        System.out.println("r1.await - " + c.await(2, TimeUnit.SECONDS));  // await返回该线程到达屏障的顺序,最快的为n-1,最慢的为0
                    } catch (BrokenBarrierException e) {
                        e.printStackTrace();
                    } catch (TimeoutException e) {
                        e.printStackTrace();
                    }
                    System.out.println("线程1通过屏障");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        
        Runnable r2 = new Runnable() {
            
            @Override
            public void run() {
                System.out.println("线程2开始进行第一步工作...");
                try {
                    Thread.sleep(1000);// 等待模式耗时操作
                    System.out.println("c2 - " + c.isBroken());
                    System.out.println("线程2第一步工作完毕,进入等待状态...当前等待线程量 - " + c.getNumberWaiting());
                    try {
                        System.out.println("r2.await - " + c.await(2, TimeUnit.SECONDS));
                    } catch (BrokenBarrierException e) {
                        e.printStackTrace();
                    } catch (TimeoutException e) {
                        e.printStackTrace();
                    }
                    System.out.println("线程2通过屏障");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        
        Runnable r3 = new Runnable() {
            
            @Override
            public void run() {
                System.out.println("线程3开始进行第一步工作...");
                try {
                    Thread.sleep(1500);// 等待模式耗时操作
//                    Thread.sleep(5000);// 等待模式耗时操作   5s的话显而易见的会报超时,由先到屏障处即await返回值为n-1的那个线程抛出TimeoutException
                                            //超时异常一经抛出,屏障被破坏,因此会导致其他已在屏障处的等待线程await抛出 BrokenBarrierException.
                                            // (依据对这个异常的处理(catch还是throws(Callable可抛出异常))来判定线程是继续执行还是抛出停止)
                                            //但是对线程3因为此线程延迟5s,所以此时还没到屏障处
                                            // 所以会继续执行,直至到达屏障处发现屏障已被破坏,抛出BrokenBarrierException
                    System.out.println("线程3第一步工作完毕,进入等待状态...当前等待线程量 - " + c.getNumberWaiting());
                    try {
                        System.out.println("r3.await - " + c.await(2, TimeUnit.SECONDS));
                    } catch (BrokenBarrierException e) {
                        System.out.println("e - " + c.isBroken());  //  设置sleep(5000)时屏障被击穿   这里为true
                        e.printStackTrace();
                    } catch (TimeoutException e) {
                        e.printStackTrace();
                    }
                    System.out.println("线程3通过屏障");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        
        new Thread(r1).start();
        new Thread(r2).start();
        new Thread(r3).start();

        System.out.println("c.getParties() - " + c.getParties()); // CyclicBarrier掌控的线程数
        
        c.reset(); // 重置,如果此时有线程在屏障处等待,那么抛出BrokenBarrierException
    }

}

运行结果:

线程1开始进行第一步工作...
线程3开始进行第一步工作...
c.getParties() - 3
线程2开始进行第一步工作...
线程1第一步工作完毕,进入等待状态...当前等待线程量 - 0
c2 - false
线程2第一步工作完毕,进入等待状态...当前等待线程量 - 1
线程3第一步工作完毕,进入等待状态...当前等待线程量 - 2
大家都执行完毕了,准备下一步工作喽
r3.await - 0
线程3通过屏障
r1.await - 2
线程1通过屏障
r2.await - 1
线程2通过屏障

PS:
【JAVA核心知识】系列导航 [持续更新中…]
上篇导航:15.1:线程控制器CountDownLatch
下篇导航:15.3:线程控制器Semaphore
欢迎关注…

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yue_hu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值