Java并发编程——CyclicBarrier和Phaser

来源:互联网 发布:mac谷歌浏览器无法登录 编辑:程序博客网 时间:2024/05/21 20:30

一、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: 开始012-19 15:19:28.470 18459-18636/? I/System.out: 开始112-19 15:19:28.470 18459-18637/? I/System.out: 开始212-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: 开始012-19 15:22:27.810 22580-22715/lbx.myapplication I/System.out: 开始212-19 15:22:27.810 22580-22714/lbx.myapplication I/System.out: 开始112-19 15:22:27.810 22580-22716/lbx.myapplication I/System.out: 开始312-19 15:22:27.820 22580-22717/lbx.myapplication I/System.out: 开始412-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: 结束412-19 15:22:30.820 22580-22713/lbx.myapplication I/System.out: 结束012-19 15:22:30.820 22580-22715/lbx.myapplication I/System.out: 结束212-19 15:22:30.820 22580-22714/lbx.myapplication I/System.out: 结束112-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();//获取屏障的数量:ncyclicBarrier.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: 开始012-19 16:28:13.310 16518-16710/lbx.myapplication I/System.out: 开始112-19 16:28:13.310 16518-16711/lbx.myapplication I/System.out: 开始212-19 16:28:13.320 16518-16712/lbx.myapplication I/System.out: 开始312-19 16:28:13.320 16518-16713/lbx.myapplication I/System.out: 开始412-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: 结束012-19 16:28:14.320 16518-16713/lbx.myapplication I/System.out: 结束412-19 16:28:14.320 16518-16710/lbx.myapplication I/System.out: 结束112-19 16:28:14.320 16518-16711/lbx.myapplication I/System.out: 结束212-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: 开始012-19 16:32:56.440 23790-25144/lbx.myapplication I/System.out: 开始112-19 16:32:56.440 23790-25145/lbx.myapplication I/System.out: 开始212-19 16:32:56.440 23790-25146/lbx.myapplication I/System.out: 开始312-19 16:32:56.440 23790-25147/lbx.myapplication I/System.out: 开始412-19 16:32:56.440 23790-25148/lbx.myapplication I/System.out: 开始512-19 16:32:56.440 23790-25149/lbx.myapplication I/System.out: 开始612-19 16:32:56.440 23790-25150/lbx.myapplication I/System.out: 开始712-19 16:32:56.440 23790-25151/lbx.myapplication I/System.out: 开始812-19 16:32:56.440 23790-25152/lbx.myapplication I/System.out: 开始912-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: 结束212-19 16:32:57.440 23790-25146/lbx.myapplication I/System.out: 结束312-19 16:32:57.440 23790-25147/lbx.myapplication I/System.out: 结束412-19 16:32:57.440 23790-25144/lbx.myapplication I/System.out: 结束112-19 16:32:57.440 23790-25143/lbx.myapplication I/System.out: 结束012-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: 结束912-19 16:32:57.440 23790-25149/lbx.myapplication I/System.out: 结束612-19 16:32:57.440 23790-25150/lbx.myapplication I/System.out: 结束712-19 16:32:57.440 23790-25148/lbx.myapplication I/System.out: 结束512-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: 开始012-19 16:35:19.050 27494-28568/lbx.myapplication I/System.out: 开始212-19 16:35:19.050 27494-28567/lbx.myapplication I/System.out: 开始112-19 16:35:19.050 27494-28569/lbx.myapplication I/System.out: 开始312-19 16:35:19.050 27494-28570/lbx.myapplication I/System.out: 开始412-19 16:35:19.050 27494-28571/lbx.myapplication I/System.out: 开始512-19 16:35:19.050 27494-28572/lbx.myapplication I/System.out: 开始612-19 16:35:19.050 27494-28573/lbx.myapplication I/System.out: 开始712-19 16:35:19.050 27494-28574/lbx.myapplication I/System.out: 开始812-19 16:35:19.050 27494-28575/lbx.myapplication I/System.out: 开始912-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: 结束412-19 16:35:20.050 27494-28568/lbx.myapplication I/System.out: 结束212-19 16:35:20.050 27494-28571/lbx.myapplication I/System.out: 结束512-19 16:35:20.050 27494-28566/lbx.myapplication I/System.out: 结束012-19 16:35:20.050 27494-28567/lbx.myapplication I/System.out: 结束112-19 16:35:20.050 27494-28572/lbx.myapplication I/System.out: 结束612-19 16:35:20.050 27494-28569/lbx.myapplication I/System.out: 结束312-19 16:35:20.050 27494-28573/lbx.myapplication I/System.out: 结束712-19 16:35:20.050 27494-28574/lbx.myapplication I/System.out: 结束812-19 16:35:20.050 27494-28575/lbx.myapplication I/System.out: 结束9


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


常用方法:

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






阅读全文
0 0