Java并发编程——CyclicBarrier和Phaser

一、CyclicBarrier

        CyclicBarrier拥有CountDownLatch的功能(CountDownLatch的介绍请看我的另一篇博客: Java并发编程——Semaphore (信号量)和CountDownLatch ),任何一个线程在没有完成时,所有线程都在等待。有点类似于屏障的意思,比如百米赛跑,需要等所有运动员都到达起跑线后,裁判才会鸣枪,这个“起跑线”就是屏障,每个运动员就是一个个线程,而“裁判鸣枪”就是后需要做的一些事情。


上栗子:


     

public static void main(String[] args) {
        final CyclicBarrier cyclicBarrier = new CyclicBarrier(5, new Runnable() {
            @Override
            public void run() {
                //执行所有线程全部完成后的逻辑
                try {
                    System.out.println("执行所有线程全部完成后的逻辑  开始");
                    Thread.sleep(3000);
                    System.out.println("执行所有线程全部完成后的逻辑   结束");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        //子线程数量
        int threadNum = 4;
        for (int i = 0; i < threadNum; i++) {
            final int finalI = i;
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        System.out.println("开始" + finalI);
                        cyclicBarrier.await();
                        System.out.println("结束" + finalI);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    }

简单粗暴,直接看log:

12-19 15:19:28.470 18459-18635/? I/System.out: 开始0
12-19 15:19:28.470 18459-18636/? I/System.out: 开始1
12-19 15:19:28.470 18459-18637/? I/System.out: 开始2
12-19 15:19:28.470 18459-18638/? I/System.out: 开始3


接下来改变线程数量:


//子线程数量
        int threadNum = 5;


再次运行看log:

12-19 15:22:27.810 22580-22713/lbx.myapplication I/System.out: 开始0
12-19 15:22:27.810 22580-22715/lbx.myapplication I/System.out: 开始2
12-19 15:22:27.810 22580-22714/lbx.myapplication I/System.out: 开始1
12-19 15:22:27.810 22580-22716/lbx.myapplication I/System.out: 开始3
12-19 15:22:27.820 22580-22717/lbx.myapplication I/System.out: 开始4
12-19 15:22:27.820 22580-22717/lbx.myapplication I/System.out: 执行所有线程全部完成后的逻辑  开始
//睡了三秒
12-19 15:22:30.820 22580-22717/lbx.myapplication I/System.out: 执行所有线程全部完成后的逻辑   结束
12-19 15:22:30.820 22580-22717/lbx.myapplication I/System.out: 结束4
12-19 15:22:30.820 22580-22713/lbx.myapplication I/System.out: 结束0
12-19 15:22:30.820 22580-22715/lbx.myapplication I/System.out: 结束2
12-19 15:22:30.820 22580-22714/lbx.myapplication I/System.out: 结束1
12-19 15:22:30.820 22580-22716/lbx.myapplication I/System.out: 结束3

常用方法:

//在此方法处线程阻塞,n个线程都执行await()后回调Runnable里的逻辑
cyclicBarrier.await();
//阻塞到3秒后则抛出TimeoutException异常,不会继续向下执行
cyclicBarrier.await(3, TimeUnit.SECONDS);
//获得到达await()(屏障)的线程的数量
cyclicBarrier.getNumberWaiting();
//当前线程的屏障是否出现损坏,例如终止线程的时候
cyclicBarrier.isBroken();
//获取屏障的数量:n
cyclicBarrier.getParties();
//重置屏障
cyclicBarrier.reset();


二、Phaser

        与CyclicBarrier功能重叠,任何一个线程在没有完成时,所有线程都在等待。


public static void main(String[] args) {
        final Phaser phaser = new Phaser(5) {
            @Override
            protected boolean onAdvance(int phase, int registeredParties) {
                //当所有线程都完成了一个任务的时候,会回调。
                System.out.println("完成了第" + phase + "个屏障");
                //true:后面的屏障无效。false:保持屏障的有效性
                return false;
            }
        };
        //线程数量
        int threadNum = 5;
        for (int i = 0; i < threadNum; i++) {
            final int finalI = i;
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        System.out.println("开始" + finalI);
                        Thread.sleep(1000);
                        //与CyclicBarrier相同,都是等待所有线程到达屏障后,再统一释放
                        phaser.arriveAndAwaitAdvance();
                        System.out.println("结束" + finalI);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    }


        重写了onAdvance方法,该方法在所有线程执行arriveAndAwaitAdvance后调用。看下log:

    

12-19 16:28:13.310 16518-16709/lbx.myapplication I/System.out: 开始0
12-19 16:28:13.310 16518-16710/lbx.myapplication I/System.out: 开始1
12-19 16:28:13.310 16518-16711/lbx.myapplication I/System.out: 开始2
12-19 16:28:13.320 16518-16712/lbx.myapplication I/System.out: 开始3
12-19 16:28:13.320 16518-16713/lbx.myapplication I/System.out: 开始4
12-19 16:28:14.320 16518-16713/lbx.myapplication I/System.out: 完成了第0个屏障
12-19 16:28:14.320 16518-16709/lbx.myapplication I/System.out: 结束0
12-19 16:28:14.320 16518-16713/lbx.myapplication I/System.out: 结束4
12-19 16:28:14.320 16518-16710/lbx.myapplication I/System.out: 结束1
12-19 16:28:14.320 16518-16711/lbx.myapplication I/System.out: 结束2
12-19 16:28:14.320 16518-16712/lbx.myapplication I/System.out: 结束3


接下来我们把线程的数量翻倍:

 //线程数量
 int threadNum = 10;

再次运行,看log:

12-19 16:32:56.440 23790-25143/lbx.myapplication I/System.out: 开始0
12-19 16:32:56.440 23790-25144/lbx.myapplication I/System.out: 开始1
12-19 16:32:56.440 23790-25145/lbx.myapplication I/System.out: 开始2
12-19 16:32:56.440 23790-25146/lbx.myapplication I/System.out: 开始3
12-19 16:32:56.440 23790-25147/lbx.myapplication I/System.out: 开始4
12-19 16:32:56.440 23790-25148/lbx.myapplication I/System.out: 开始5
12-19 16:32:56.440 23790-25149/lbx.myapplication I/System.out: 开始6
12-19 16:32:56.440 23790-25150/lbx.myapplication I/System.out: 开始7
12-19 16:32:56.440 23790-25151/lbx.myapplication I/System.out: 开始8
12-19 16:32:56.440 23790-25152/lbx.myapplication I/System.out: 开始9
12-19 16:32:57.440 23790-25146/lbx.myapplication I/System.out: 完成了第0个屏障
12-19 16:32:57.440 23790-25145/lbx.myapplication I/System.out: 结束2
12-19 16:32:57.440 23790-25146/lbx.myapplication I/System.out: 结束3
12-19 16:32:57.440 23790-25147/lbx.myapplication I/System.out: 结束4
12-19 16:32:57.440 23790-25144/lbx.myapplication I/System.out: 结束1
12-19 16:32:57.440 23790-25143/lbx.myapplication I/System.out: 结束0
12-19 16:32:57.440 23790-25152/lbx.myapplication I/System.out: 完成了第1个屏障
12-19 16:32:57.440 23790-25152/lbx.myapplication I/System.out: 结束9
12-19 16:32:57.440 23790-25149/lbx.myapplication I/System.out: 结束6
12-19 16:32:57.440 23790-25150/lbx.myapplication I/System.out: 结束7
12-19 16:32:57.440 23790-25148/lbx.myapplication I/System.out: 结束5
12-19 16:32:57.440 23790-25151/lbx.myapplication I/System.out: 结束8

因为onAdvance返回的是false,第一次执行过onAdvance后,屏障依然有效,所以后面的代码正常执行,当我们把onAdvance返回true的时候,仍然用10条子线程:

 final Phaser phaser = new Phaser(5) {
            @Override
            protected boolean onAdvance(int phase, int registeredParties) {
                //当所有线程都完成了一个任务的时候,会回调。
                System.out.println("完成了第" + phase + "个屏障");
                //true:后面的屏障无效。false:保持屏障的有效性
                return true;
            }
        };

运行代码,看log:

12-19 16:35:19.050 27494-28566/lbx.myapplication I/System.out: 开始0
12-19 16:35:19.050 27494-28568/lbx.myapplication I/System.out: 开始2
12-19 16:35:19.050 27494-28567/lbx.myapplication I/System.out: 开始1
12-19 16:35:19.050 27494-28569/lbx.myapplication I/System.out: 开始3
12-19 16:35:19.050 27494-28570/lbx.myapplication I/System.out: 开始4
12-19 16:35:19.050 27494-28571/lbx.myapplication I/System.out: 开始5
12-19 16:35:19.050 27494-28572/lbx.myapplication I/System.out: 开始6
12-19 16:35:19.050 27494-28573/lbx.myapplication I/System.out: 开始7
12-19 16:35:19.050 27494-28574/lbx.myapplication I/System.out: 开始8
12-19 16:35:19.050 27494-28575/lbx.myapplication I/System.out: 开始9
12-19 16:35:20.050 27494-28570/lbx.myapplication I/System.out: 完成了第0个屏障
12-19 16:35:20.050 27494-28570/lbx.myapplication I/System.out: 结束4
12-19 16:35:20.050 27494-28568/lbx.myapplication I/System.out: 结束2
12-19 16:35:20.050 27494-28571/lbx.myapplication I/System.out: 结束5
12-19 16:35:20.050 27494-28566/lbx.myapplication I/System.out: 结束0
12-19 16:35:20.050 27494-28567/lbx.myapplication I/System.out: 结束1
12-19 16:35:20.050 27494-28572/lbx.myapplication I/System.out: 结束6
12-19 16:35:20.050 27494-28569/lbx.myapplication I/System.out: 结束3
12-19 16:35:20.050 27494-28573/lbx.myapplication I/System.out: 结束7
12-19 16:35:20.050 27494-28574/lbx.myapplication I/System.out: 结束8
12-19 16:35:20.050 27494-28575/lbx.myapplication I/System.out: 结束9


我们发现,onAdvance只执行了一次,因为反悔了true,使屏障无效了,那么也就没有屏障的概念了。


常用方法:

//获得当前parties的个数
phaser.getRegisteredParties();
//使parties的个数加1
phaser.register();
//使parties的个数加3
phaser.bulkRegister(3);
//获得当前已经被使用的parties的个数
phaser.getArrivedParties();
//获得当前未被使用的parties的个数
phaser.getUnarrivedParties();
//使parties的个数加1,并继续往下执行,回调onAdvance()方法
phaser.arrive();
//若传入的参数与getPhase()的值一样,则处于屏障阻塞状态,否则继续往下执行过。该方法不参与计算,只起判断作用
phaser.awaitAdvance(3);






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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值