关于java:CyclicBarrier回环栅栏

1次阅读

共计 4622 个字符,预计需要花费 12 分钟才能阅读完成。

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
@Setter
public 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 总结:

  1. 结构参数中,线程数量必须和 await 的线程数量相等,否则永远阻塞。
  2. 结构参数中的 Runnable 作用是在所有线程都达到屏障后优先执行此线程,,能够做一些统计工作,这可能是栅栏的含意。
  3. await 办法能够屡次调用,实现屡次运行,这可能是回环含意。
正文完
 0