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 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 result;
Athletes(ConcurrentHashMap 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 result;
CompetitionResult(ConcurrentHashMap 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 sortMapByValue(Map map) {
int size = map.size();
List> list = new ArrayList<>(size);
list.addAll(map.entrySet());
List keys = list.stream()
.sorted(Comparator.comparing(Map.Entry::getValue))
.map(Map.Entry::getKey)
.collect(Collectors.toList());
List 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 result = new ConcurrentHashMap<>();
/** barrierAction线程统计 **/
private static CyclicBarrier cyclicBarrier = new CyclicBarrier(8, new CompetitionResult(result));
public static void main(String[] args) {
List 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方法可以多次调用,实现多次运行,这可能是回环含义。