非主流并发工具之 CyclicBarrier

CyclicBarrier 的功能类似于前面说到的 CountDownLatch,用于让多个线程(子任务)互相等待,直到共同到达公共屏障点(common barrier point),在这个点上,所有的子任务都已完成,从而主任务完成。

该类构造的时候除了必须要指定线程数量,还可以传入一个 Runnable 对象,它的 run 方法将在到达公共屏障点后执行一次。子线程完成计算后,分别调用 CyclicBarrier#await 方法进入阻塞状态,直到其他所有子线程都调用了 await

下面仍然以运动员准备赛跑为例来说明 CyclicBarrier 的用法:

            final int count = 8;
            System.out.println("运动员开始就位。");

            final CyclicBarrier cb = new CyclicBarrier(count, new Runnable() {
                @Override
                public void run() {
                    System.out.println("比赛开始...");
                }
            });

            for (int i = 1; i <= count; i++) {
                final int number = i;
                new Thread() {
                    @Override
                    public void run() {
                        System.out.println(number + " 号运动员到场并开始准备...");
                        try {
                            // 准备 2~5 秒钟。
                            TimeUnit.SECONDS.sleep(new Random().nextInt(4) + 2);
                        } catch (InterruptedException ex) {
                        }
                        System.out.println(number + " 号运动员就位。");
                        try {
                            cb.await();
                        } catch (InterruptedException | BrokenBarrierException ex) {
                        }
                    }
                }.start();
            }
            System.out.println("等待所有运动员就位...");
    

运行输出(可能)为:

运动员开始就位。
1 号运动员到场并开始准备...
2 号运动员到场并开始准备...
等待所有运动员就位...
3 号运动员到场并开始准备...
4 号运动员到场并开始准备...
6 号运动员到场并开始准备...
8 号运动员到场并开始准备...
5 号运动员到场并开始准备...
7 号运动员到场并开始准备...
1 号运动员就位。
3 号运动员就位。
8 号运动员就位。
6 号运动员就位。
2 号运动员就位。
7 号运动员就位。
5 号运动员就位。
4 号运动员就位。
比赛开始...

最后看看 CyclicBarrierCountDownLatch 的主要异同:

  1. 两者在构造的时候都必须指定线程数量,而且该数量在构造后不可修改。
  2. 前者可以传入一个 Runnable 对象,在任务完成后自动调用,执行者为某个子线程;后者可在 await 方法后手动执行一段代码实现相同的功能,但执行者为主线程。
  3. 前者在每个子线程上都进行阻塞,然后一起放行;后者仅在主线程上阻塞一次。
  4. 前者可以重复使用;后者的倒计数器归零后就作废了。
  5. 两者的内部实现完全不同。

你可能感兴趣的:(非主流并发工具之 CyclicBarrier)