一步步学习多线程(九) CyclicBarrier

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/money9sun/article/details/87092012

CyclicBarrier位于java.util.concurrent包下,可以叫它回环栅栏,我们可以简单的理解为可以无限次重置的计数器。

构造函数:

1、public CyclicBarrier(int parties, Runnable barrierAction)

2、public CyclicBarrier(int parties)

参数 parties (the number of threads that must invoke {@link #await} before the barrier is tripped)中文翻译就是在栅栏倒之前有多少线程必须调用

参数barrierAction(the command to execute when the barrier is tripped)中文翻译就是栅栏倒之后要做什么事情

主要方法:

1、public int await()

2、public int await(long timeout, TimeUnit unit)

区别就是第二个方法会让这些线程等待至一定的时间,如果还有线程没有到达barrier状态就直接让到达barrier的线程执行后续任务

例子一:10个工人,要把材料都整齐才能进行下一步工作

public class CyclicBarrierWork {

    static int N = 10;
    static CyclicBarrier cyclicBarrier = new CyclicBarrier(N);


    public static void main(String[] args) {
        ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("demo-pool-%d").build();
        ExecutorService threadPool = new ThreadPoolExecutor(10, 10,
                0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(1024), threadFactory, new ThreadPoolExecutor.AbortPolicy());

        for (int i = 0; i < N; i++) {
            threadPool.execute(new Worker(cyclicBarrier,i));
        }
    }

}

class Worker implements Runnable{
    private CyclicBarrier cyclicBarrier;
    private int num;
    public Worker(CyclicBarrier cyclicBarrier,int num) {
        this.cyclicBarrier = cyclicBarrier;
        this.num = num;
    }

    @Override
    public void run() {
        try {
            System.out.println("工人" + num + "开始运送材料");
            Thread.sleep((int)Math.random()*2000);
            System.out.println("工人" + num + "运送材料完成,等待其他工人");
            cyclicBarrier.await();
        } catch (InterruptedException | BrokenBarrierException e) {
            e.printStackTrace();
        }
        System.out.println("工人" + num + "所有材料运送完成,可以开始下一步工作");
    }
}

结果:

工人0开始运送材料
工人1开始运送材料
工人2开始运送材料
工人0运送材料完成,等待其他工人
工人1运送材料完成,等待其他工人
工人3开始运送材料
工人2运送材料完成,等待其他工人
工人4开始运送材料
工人5开始运送材料
工人6开始运送材料
工人3运送材料完成,等待其他工人
工人4运送材料完成,等待其他工人
工人7开始运送材料
工人6运送材料完成,等待其他工人
工人5运送材料完成,等待其他工人
工人7运送材料完成,等待其他工人
工人8开始运送材料
工人9开始运送材料
工人8运送材料完成,等待其他工人
工人9运送材料完成,等待其他工人
工人9所有材料运送完成,可以开始下一步工作
工人0所有材料运送完成,可以开始下一步工作
工人4所有材料运送完成,可以开始下一步工作
工人3所有材料运送完成,可以开始下一步工作
工人5所有材料运送完成,可以开始下一步工作
工人8所有材料运送完成,可以开始下一步工作
工人1所有材料运送完成,可以开始下一步工作
工人2所有材料运送完成,可以开始下一步工作
工人7所有材料运送完成,可以开始下一步工作
工人6所有材料运送完成,可以开始下一步工作

例子二:10个工人,要把材料都整齐才能进行下一步工作,同时报告一下总管

和上面的不同在于构造函数

static CyclicBarrier cyclicBarrier = new CyclicBarrier(N, () -> {
    System.out.println("报告总管,材料都齐了,我们开始其他工作了");
});

结果如下:注意红色标注,同时大家打印一下线程信息就知道,系统并没有新建线程而是从当前线程中选了一个作为执行者

工人0开始运送材料
工人0运送材料完成,等待其他工人
工人1开始运送材料
工人2开始运送材料
工人1运送材料完成,等待其他工人
工人3开始运送材料
工人4开始运送材料
工人5开始运送材料
工人2运送材料完成,等待其他工人
工人6开始运送材料
工人3运送材料完成,等待其他工人
工人4运送材料完成,等待其他工人
工人5运送材料完成,等待其他工人
工人6运送材料完成,等待其他工人
工人7开始运送材料
工人8开始运送材料
工人9开始运送材料
工人8运送材料完成,等待其他工人
工人9运送材料完成,等待其他工人
工人7运送材料完成,等待其他工人
报告总管,材料都齐了,我们开始其他工作了
工人9所有材料运送完成,可以开始下一步工作
工人7所有材料运送完成,可以开始下一步工作
工人8所有材料运送完成,可以开始下一步工作
工人5所有材料运送完成,可以开始下一步工作
工人6所有材料运送完成,可以开始下一步工作
工人4所有材料运送完成,可以开始下一步工作
工人3所有材料运送完成,可以开始下一步工作
工人2所有材料运送完成,可以开始下一步工作
工人1所有材料运送完成,可以开始下一步工作
工人0所有材料运送完成,可以开始下一步工作

例子三:模拟并发

public class CountDownLatchConcurrency {

    static int N = 10;
    static CyclicBarrier cyclicBarrier = new CyclicBarrier(N);


    public static void main(String[] args) throws InterruptedException {
        ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("demo-pool-%d").build();
        ExecutorService threadPool = new ThreadPoolExecutor(10, 10,
                0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(1024), threadFactory, new ThreadPoolExecutor.AbortPolicy());

        for (int i = 0; i < N; i++) {
            int finalI = i;
            threadPool.execute(() -> {
                try {
                    // 每个线程休眠0-2秒
                    Thread.sleep((int)(Math.random()*2000));
                    System.out.println("线程" + finalI + "准备完毕");
                    // 等待其他的线程准备
                    cyclicBarrier.await();
                    System.out.println("线程" + finalI + "开始");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            });
        }

        threadPool.shutdown();
        while(true){
            if(threadPool.isTerminated()){
                System.out.println("所有的子线程都结束了!");
                break;
            }
            Thread.sleep(1000);
        }
    }
}

结果:

线程6准备完毕
线程2准备完毕
线程9准备完毕
线程4准备完毕
线程0准备完毕
线程5准备完毕
线程7准备完毕
线程3准备完毕
线程1准备完毕
线程8准备完毕
线程8开始
线程6开始
线程0开始
线程7开始
线程1开始
线程3开始
线程5开始
线程4开始
线程9开始
线程2开始
所有的子线程都结束了!

猜你喜欢

转载自blog.csdn.net/money9sun/article/details/87092012