• Java多线程之CyclicBarrier


    背景

    CyclicBarrier是java.util.concurrent包下提供的另外一个常用的线程组同步工具类,顾名思义,是个可循环利用的栅栏。同样参考javadoc上的定义: “A synchronization aid that allows a set of threads to all wait for each other to reach a common barrier point. CyclicBarriers are useful in programs involving a fixed sized party of threads that must occasionally wait for each other.” 用于一组子线程间各线程进行等待的场景。

    关键方法

    a) 构造方法

    public CyclicBarrier(int parties);
    public CyclicBarrier(int parties, Runnable barrierAction);

    入参是参数方的线程数量,barrierAction是指当所有线程都到达同一栅栏后,需要做的响应,如果非空则在最后一线程到达栅栏时,由最后到达的线程,进行执行。

    b) await方法

    public int await() throws InterruptedException, BrokenBarrierException;

    由参与线程进行调用,报告自身任务已经完成或就绪。如果

    一个示例

    将前面的倒数10个数进行火箭发射的例子,其实也是可以用CyclicBarrier来实现的。

    import java.util.concurrent.CyclicBarrier;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.atomic.AtomicInteger;
    
    public class RocketFireCyclicBarrierImpl {
    
        private static final CyclicBarrier barrier = new CyclicBarrier(2,
            () -> System.out.println("点火!!"));
        private static final AtomicInteger counter = new AtomicInteger(10);
    
        public static void main(String[] args) {
    
            System.out.println("开始倒数");
            ExecutorService fixedThreadPool = Executors.newFixedThreadPool(2);
            fixedThreadPool.submit(new NumberPrinter(true, barrier));
            fixedThreadPool.submit(new NumberPrinter(false, barrier));
            fixedThreadPool.shutdown();
        }
    
        private static class NumberPrinter implements Runnable {
    
            private final boolean       evenNumberPrinter;
            private final CyclicBarrier cyclicBarrier;
    
            public NumberPrinter(boolean evenNumberPrinter, CyclicBarrier cyclicBarrier) {
                this.evenNumberPrinter = evenNumberPrinter;
                this.cyclicBarrier = cyclicBarrier;
            }
    
            @Override
            public void run() {
    
                while (true) {
                    synchronized (counter) {
                        int v = counter.get();
                        if (v < 1) {
                            break;
                        }
    
                        if ((evenNumberPrinter && v % 2 == 0) || (!evenNumberPrinter && v % 2 == 1)) {
                            System.out.println(counter.getAndDecrement());
                        }
                    }
                }
    
                try {
                    cyclicBarrier.await();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    CyclicBarrier与CountDownLatch的异同和总结

    两个同步工具类在某些场景下,能实现相似的功能,也有一些使用场景上的不同。

    相同之处:两者都有类似的线程组同步机制,都能实现一组线程任务结束通知的处理。

    CountDownLatch CyclicBarrier
    减计数方式 加计数方式
    计算为0时释放所有等待的线程 计数达到指定值时释放所有等待线程
    计数为0时,无法重置 计数达到指定值时,计数置为0重新开始
    调用countDown()方法计数减一,调用await()方法只进行阻塞,对计数没任何影响 调用await()方法计数加1,若加1后的值不等于构造方法的值,则线程阻塞
    不可重复利用 可重复利用

    通用使用场景的总结:CountDownLatch通常是主线程任务进行拆分到子线程进行各自处理,最后由主线程进行汇总,到达的后置任务由主线程负责完成。例如生活化的场景,CountDownLatch适合跑步比赛模拟场边的裁判,在比赛开始前等所有运动员在跑道前就位后进行鸣枪开始比赛,以及在比赛结束后统计成绩。

    CyclicBarrier则是完成由子线程组内部进行等待协同,由最后到达者完成到达后置任务,主线程并不参与,并且CyclicBarrier是可循环计数的。例如生活化的场景,CyclicBarrier适合模拟各种集合的场景,最晚到的人,得自罚三杯一样。

  • 相关阅读:
    【OCP12c】CUUG最新考试原题整理及答案(07110)
    OCP 12c最新考试原题及答案(0718)
    【OCP12c】CUUG最新考试原题整理及答案(0719)
    OCP 12c最新考试原题及答案(0714)
    《PHP与MySQL程序设计》面向对象的PHP
    Linux常用命令之文件管理
    《锋利的jQuery》之jQuery简介
    《锋利的jQuery》之jQuery与Ajax
    Google AppEngine上部署PHP应用
    《PHP与MySQL程序设计》第三章 PHP基础
  • 原文地址:https://www.cnblogs.com/jacksonshi/p/14398834.html
Copyright © 2020-2023  润新知