【并发编程】- CyclicBarrier 屏障重置性

254 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第17天,点击查看活动详情

CyclicBarrier 屏障重置性及getNumberWaiting()方法的使用

线程执行代码如下:

public class ThreadA implements Runnable {

    private CyclicBarrier cyclicBarrier;

    public ThreadA(CyclicBarrier cyclicBarrier){
        super();
        this.cyclicBarrier=cyclicBarrier;
    }

    @Override
    public void run() {
        try {
            cyclicBarrier.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
    }
}

运行类执行代码如下:

public class CyclicBarrierGetNumberWaitingRun {
    public static void main(String[] args) throws InterruptedException {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(2);
        ThreadA thread1 = new ThreadA(cyclicBarrier);
        new Thread(thread1).start();
        Thread.sleep(5000);
        System.out.println("在屏障点等待的线程数:"+cyclicBarrier.getNumberWaiting());

        ThreadA thread2 = new ThreadA(cyclicBarrier);
        new Thread(thread2).start();
        Thread.sleep(5000);
        System.out.println("在屏障点等待的线程数:"+cyclicBarrier.getNumberWaiting());

        ThreadA thread3 = new ThreadA(cyclicBarrier);
        new Thread(thread3).start();
        Thread.sleep(5000);
        System.out.println("在屏障点等待的线程数:"+cyclicBarrier.getNumberWaiting());

        ThreadA thread4 = new ThreadA(cyclicBarrier);
        new Thread(thread4).start();
        Thread.sleep(5000);
        System.out.println("在屏障点等待的线程数:"+cyclicBarrier.getNumberWaiting());
    }
}

运行结果如下:

在屏障点等待的线程数:1
在屏障点等待的线程数:0
在屏障点等待的线程数:1
在屏障点等待的线程数:0

从运行结果来看,CyclicBarrier具有屏障重置性,就是parties的值可以重置归0。

使用CyclicBarrier类实现阶段跑步比赛

使用CyclicBarrier类具有计数重置性实现多赛段的比赛

实现类代码如下:

public class CyclicBarrierService {
    private CyclicBarrier cyclicBarrier;

    public CyclicBarrierService(CyclicBarrier cyclicBarrier){
        super();
        this.cyclicBarrier=cyclicBarrier;
    }

    public void startRun(){
        try {
            long sleepValue=(int)(Math.random()*10000);
            Thread.sleep(sleepValue);
            System.out.println(Thread.currentThread().getName()+" "+System.currentTimeMillis()+" 开始跑第1阶段"+" "+(cyclicBarrier.getNumberWaiting()+1));
            cyclicBarrier.await();
            System.out.println(Thread.currentThread().getName()+" "+System.currentTimeMillis()+"  结束跑第1阶段"+" "+cyclicBarrier.getNumberWaiting());

            Thread.sleep(sleepValue);
            System.out.println(Thread.currentThread().getName()+" "+System.currentTimeMillis()+" 开始跑第2阶段"+" "+(cyclicBarrier.getNumberWaiting()+1));
            cyclicBarrier.await();
            System.out.println(Thread.currentThread().getName()+" "+System.currentTimeMillis()+"  结束跑第2阶段"+" "+cyclicBarrier.getNumberWaiting());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
    }
}

线程执行代码如下:

public class MatchThread implements Runnable {

    private CyclicBarrierService cyclicBarrierService;

    public MatchThread(CyclicBarrierService service){
        super();
        this.cyclicBarrierService=service;
    }


    @Override
    public void run() {
        cyclicBarrierService.startRun();
    }
}

运行类代码如下:

public class CyclicBarrierMatchRun {
    public static void main(String[] args) {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(2);
        CyclicBarrierService cyclicBarrierService = new CyclicBarrierService(cyclicBarrier);

        for (int i = 0; i <4 ; i++) {
            MatchThread matchThread = new MatchThread(cyclicBarrierService);
            Thread thread = new Thread(matchThread);
            thread.setName("运动员"+(i+1)+"号");
            thread.start();
        }
    }
}

运行结果如下:

运动员3号 1650358303994 开始跑第1阶段 1
运动员4号 1650358305647 开始跑第1阶段 2
运动员4号 1650358305647  结束跑第1阶段 0
运动员3号 1650358305647  结束跑第1阶段 0
运动员2号 1650358306261 开始跑第1阶段 1
运动员3号 1650358306966 开始跑第2阶段 2
运动员2号 1650358306966  结束跑第1阶段 0
运动员3号 1650358306966  结束跑第2阶段 0
运动员1号 1650358307071 开始跑第1阶段 1
运动员4号 1650358308619 开始跑第2阶段 2
运动员4号 1650358308619  结束跑第2阶段 0
运动员1号 1650358308619  结束跑第1阶段 0
运动员2号 1650358310550 开始跑第2阶段 1
运动员1号 1650358313014 开始跑第2阶段 2
运动员1号 1650358313014  结束跑第2阶段 0
运动员2号 1650358313014  结束跑第2阶段 0

说明CyclicBarrier类的parties值从1到2,然后再恢复成0的过程,证明CyclicBarrier类的屏障点是可以复用的。

其实线程1234每到达一个屏障点时的组合有可能是随机的,有可能3和4到达第一屏障,而到达第二屏障时的组合可能有很多。