• Concurrent同步工具类02


    简介

    CyclicBarrier 的字面意思是可循环使用(Cyclic)的屏障(Barrier)。它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活。CyclicBarrier默认的构造方法是CyclicBarrier(int parties),其参数表示屏障拦截的线程数量,每个线程调用await方法告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞。

    CyclicBarrier一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier。

    需要所有的子任务都完成时,才执行主任务,这个时候就可以选择使用CyclicBarrier。

    CyclicBarrier的应用场景

    CyclicBarrier可以用于多线程计算数据,最后合并计算结果的应用场景。需要所有的子任务都完成时,才执行主任务,这个时候就可以选择使用CyclicBarrier。比如我们用一个Excel保存了用户所有银行流水,每个Sheet保存一个帐户近一年的每笔银行流水,现在需要统计用户的日均银行流水,先用多线程处理每个sheet里的银行流水,都执行完之后,得到每个sheet的日均银行流水,最后,再用barrierAction用这些线程的计算结果,计算出整个Excel的日均银行流水。

    应用举例:

     1 package com.test.lesson01;
     2 
     3 import java.io.IOException;
     4 import java.util.Random;
     5 import java.util.concurrent.BrokenBarrierException;
     6 import java.util.concurrent.CyclicBarrier;
     7 import java.util.concurrent.ExecutorService;
     8 import java.util.concurrent.Executors;
     9 
    10 public class CyclicBarrierTest1 {
    11 
    12     public static void main(String[] args) throws IOException, InterruptedException {
    13         //如果将参数改为4,但是下面只加入了3个选手,这永远等待下去
    14         CyclicBarrier barrier = new CyclicBarrier(3);
    15 
    16         ExecutorService executor = Executors.newFixedThreadPool(3);
    17         executor.submit(new Thread(new Runner(barrier, "1号选手")));
    18         executor.submit(new Thread(new Runner(barrier, "2号选手")));
    19         executor.submit(new Thread(new Runner(barrier, "3号选手")));
    20 
    21         executor.shutdown();
    22     }
    23 }
    24 
    25 class Runner implements Runnable {
    26     // 一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点
    27     private CyclicBarrier barrier;
    28 
    29     private String name;
    30 
    31     public Runner(CyclicBarrier barrier, String name) {
    32         super();
    33         this.barrier = barrier;
    34         this.name = name;
    35     }
    36 
    37     @Override
    38     public void run() {
    39         try {
    40             Thread.sleep(1000 * (new Random()).nextInt(8));
    41             System.out.println(name + " 准备好了...");
    42             // barrier的await方法,在所有参与者都已经在此 barrier 上调用 await 方法之前,将一直等待。
    43             barrier.await();
    44             //设置等待时间,如果等待了1秒,最后一个线程还没有就位,则自己继续运行,但是会导致Barrier被标记为一个已经破坏的Barrier
    45             //barrier.await(1,TimeUnit.SECONDS);
    46         } catch (InterruptedException e) {
    47             System.out.println(name + " 中断异常!");
    48         } catch (BrokenBarrierException e) {
    49             System.out.println(name + " Barrier损坏异常!");
    50         }
    51         System.out.println(name + " 起跑!");
    52     }
    53 }
    View Code

    其中的一种运行结果为:(但是起跑一定在准备好了之后)

    1 2号选手 准备好了...
    2 3号选手 准备好了...
    3 1号选手 准备好了...
    4 1号选手 起跑!
    5 2号选手 起跑!
    6 3号选手 起跑!
    View Code

    CyclicBarrier与CountDownLatch的区别

    至此我们难免会将CyclicBarrier与CountDownLatch进行一番比较。这两个类都可以实现一组线程在到达某个条件之前进行等待,它们内部都有一个计数器,当计数器的值不断的减为0的时候所有阻塞的线程将会被唤醒。

    有区别的是CyclicBarrier的计数器由自己控制,而CountDownLatch的计数器则由使用者来控制,在CyclicBarrier中线程调用await方法不仅会将自己阻塞还会将计数器减1,而在CountDownLatch中线程调用await方法只是将自己阻塞而不会减少计数器的值。

    另外,CountDownLatch只能拦截一轮,而CyclicBarrier可以实现循环拦截。一般来说用CyclicBarrier可以实现CountDownLatch的功能,而反之则不能,例如上面的赛马程序就只能使用CyclicBarrier来实现。

    参考文献:

    http://ifeve.com/concurrency-cyclicbarrier/#more-14746

    https://blog.csdn.net/qq_39241239/article/details/87030142

  • 相关阅读:
    PKU JudgeOnline 题目分类
    调试时拼凑带端口的完整网址/域名
    智能电脑监控器,完美解决想监控别人在自己电脑上的一切操作。
    如何清理LDF文件
    使用母版页后FindConttol需要注意
    【外刊IT评论】代码覆盖率:80%,不能少
    推荐2本普通人参悟的书
    处理在母版页加AJAX环境下处理滚动条回发保持不动的问题
    虚拟目录中的web.config不被上级目录的web.config影响的处理
    C++中^符号的意思
  • 原文地址:https://www.cnblogs.com/Hermioner/p/14193043.html
Copyright © 2020-2023  润新知