CyclicBarrier,回环栅栏,是并发包下的一个并发工具类。
场景举例:奥运会百米赛场,等每个运动员筹备就位后,再开始筹备较量。
运动员类
/** * 运动员类 * * @author zhangjianbing * time 2020/8/16 */public class Athletes implements Runnable { private CyclicBarrier cyclicBarrier; private String name; public Athletes(CyclicBarrier cyclicBarrier, String name) { this.cyclicBarrier = cyclicBarrier; this.name = name; } @Override public void run() { System.out.println(name + "就位"); try { cyclicBarrier.await(); Random random = new Random(); double time = random.nextDouble() + 9; System.out.println(name + ": " + time); } catch (Exception e) { } }}
测试类
/** * @author zhangjianbing * time 2020/8/16 */public class Test01 { private static CyclicBarrier cyclicBarrier = new CyclicBarrier(8); public static void main(String[] args) { List<Athletes> athleteList = new ArrayList<>(); athleteList.add(new Athletes(cyclicBarrier, "博尔特")); athleteList.add(new Athletes(cyclicBarrier, "鲍威尔")); athleteList.add(new Athletes(cyclicBarrier, "盖伊")); athleteList.add(new Athletes(cyclicBarrier, "布雷克")); athleteList.add(new Athletes(cyclicBarrier, "加特林")); athleteList.add(new Athletes(cyclicBarrier, "苏炳添")); athleteList.add(new Athletes(cyclicBarrier, "路人甲")); athleteList.add(new Athletes(cyclicBarrier, "路人乙")); Executor executor = Executors.newFixedThreadPool(8); for (Athletes athlete : athleteList) { executor.execute(athlete); } ((ExecutorService) executor).shutdown(); }}
测试后果:
博尔特就位布雷克就位鲍威尔就位盖伊就位苏炳添就位加特林就位路人乙就位路人甲就位加特林问题: 9.776372123476314盖伊问题: 9.967978419291022路人乙问题: 9.748737769710981博尔特问题: 9.046833555812153路人甲问题: 9.933822348966673苏炳添问题: 9.34526967787858布雷克问题: 9.717048683854648鲍威尔问题: 9.548901062288996
CyclicBarrier结构参数中除了传线程数量,还能够传一个Runnable,作用是在所有期待线程被唤醒后首先执行此线程,而后再进行后续操作。
革新下面的示例
运动员类,根本不变,减少了一次阻塞,目标是为了期待所有运动员就绪,还减少了个容器,目标是寄存比赛结果。
/** * 运动员类 * * @author zhangjianbing * time 2020/8/16 */public class Athletes implements Runnable { private CyclicBarrier cyclicBarrier; private String name; private ConcurrentHashMap<String, Double> result; Athletes(ConcurrentHashMap<String, Double> result, CyclicBarrier cyclicBarrier, String name) { this.result = result; this.cyclicBarrier = cyclicBarrier; this.name = name; } @Override public void run() { System.out.println(name + "就位"); try { cyclicBarrier.await();// 首次阻塞,目标期待全员就绪 Random random = new Random(); double time = random.nextDouble() + 9; System.out.println(name + "问题: " + time); result.put(name, time);// 比赛结果汇总 cyclicBarrier.await();// 再次阻塞,目标统计比赛结果 } catch (Exception e) { e.getStackTrace(); } }}
barrierAction类,此类的作用就是统计运动员问题。
/** * @author zhangjianbing * time 2020/8/16 */@Getter@Setterpublic class CompetitionResult implements Runnable { private ConcurrentHashMap<String, Double> result; CompetitionResult(ConcurrentHashMap<String, Double> result) { this.result = result; } @Override public void run() { if (!result.isEmpty()) { System.out.println("==========较量完结问题汇总=========="); System.out.println(sortMapByValue(result)); } else { System.out.println("==========较量开始=========="); } } /** 从小到大排序 **/ private List<String> sortMapByValue(Map<String, Double> map) { int size = map.size(); List<Map.Entry<String, Double>> list = new ArrayList<>(size); list.addAll(map.entrySet()); List<String> keys = list.stream() .sorted(Comparator.comparing(Map.Entry<String, Double>::getValue)) .map(Map.Entry::getKey) .collect(Collectors.toList()); List<String> rankList = new ArrayList<>(); for (int i = 0; i < keys.size(); i++) { rankList.add("第" + (i + 1) + "名:" + keys.get(i)); } return rankList; }}
测试类,减少了CyclicBarrier结构参数以及一个全局的map容器用来寄存比赛结果。
/** * @author zhangjianbing * time 2020/8/16 */public class Test01 { /** 将统计的后果都放到map中保留,以便统计问题 **/ private static ConcurrentHashMap<String, Double> result = new ConcurrentHashMap<>(); /** barrierAction线程统计 **/ private static CyclicBarrier cyclicBarrier = new CyclicBarrier(8, new CompetitionResult(result)); public static void main(String[] args) { List<Athletes> athleteList = new ArrayList<>(); athleteList.add(new Athletes(result, cyclicBarrier, "博尔特")); athleteList.add(new Athletes(result, cyclicBarrier, "鲍威尔")); athleteList.add(new Athletes(result, cyclicBarrier, "盖伊")); athleteList.add(new Athletes(result, cyclicBarrier, "布雷克")); athleteList.add(new Athletes(result, cyclicBarrier, "加特林")); athleteList.add(new Athletes(result, cyclicBarrier, "苏炳添")); athleteList.add(new Athletes(result, cyclicBarrier, "路人甲")); athleteList.add(new Athletes(result, cyclicBarrier, "路人乙")); Executor executor = Executors.newFixedThreadPool(8); for (Athletes athlete : athleteList) { executor.execute(athlete); } ((ExecutorService) executor).shutdown(); }}
运行后果:
博尔特就位布雷克就位盖伊就位苏炳添就位鲍威尔就位加特林就位路人甲就位路人乙就位==========较量开始==========路人甲问题: 9.987082768602964盖伊问题: 9.437668731148879加特林问题: 9.173731719193814路人乙问题: 9.169443283692779博尔特问题: 9.11962473264503鲍威尔问题: 9.138726087475982苏炳添问题: 9.607073596518454布雷克问题: 9.294505506699329==========较量完结问题汇总==========[第1名:博尔特, 第2名:鲍威尔, 第3名:路人乙, 第4名:加特林, 第5名:布雷克, 第6名:盖伊, 第7名:苏炳添, 第8名:路人甲]
CyclicBarrier总结:
- 结构参数中,线程数量必须和await的线程数量相等,否则永远阻塞。
- 结构参数中的Runnable作用是在所有线程都达到屏障后优先执行此线程,,能够做一些统计工作,这可能是栅栏的含意。
- await办法能够屡次调用,实现屡次运行,这可能是回环含意。