CyclicBarrier【循环栅栏】的使用
https://blog.csdn.net/qq_39241239/article/details/87030142
例子来源自上链接。
个人做了稍许改变,大体一致功能一致。
功能为:打印马赛跑的轨迹,直到有马胜出,结束比赛。
class Horse implements Runnable{ private String name; private int strides = 0; private final CyclicBarrier cyclicBarrier; public Horse(String name, CyclicBarrier cyclicBarrier) { this.name = name; this.cyclicBarrier = cyclicBarrier; } public String getName(){ return name; } /** * 跑 */ public void work() { synchronized (this){ strides += new Random().nextInt(3); } try { //等待所有马都跑完 cyclicBarrier.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } } public int getStrides(){ synchronized (this){ return strides; } } @Override public void run() { //此处一定需要循环,否则打印了第一轮之后不会继续打印
//!Thread.currentThread().isInterrupted(); while (!Thread.interrupted()){ work(); }
//此处代码只有在线程池关闭之后才会执行 5次,因为是while循环。
//System.out.println("----------===-----------"); } public boolean isWin(int total){ boolean flag = Boolean.FALSE; if(getStrides() >= total){ flag = Boolean.TRUE; System.out.println(getName()+" won !!"); } return flag; } }
class HorseRace implements Runnable{ private static final int TOTAL = 32; private final List<Horse> horses = new ArrayList<>(); private static ExecutorService service; HorseRace(ExecutorService service){ HorseRace.service = service; } public void addHorse(Horse horse){ horses.add(horse); } /** * 打印边界 */ private void getLine(){ StringBuffer line = new StringBuffer(); for(int i = 0; i < TOTAL ;i++){ line.append("="); } System.out.println(line); } /** * 一轮跑完,打印每匹马的轨迹 */ public void getTrace(){ getLine(); for(Horse horse : horses){ StringBuffer trace = getHorseTrace(horse).append(horse.getName()); System.out.println(trace); } for (Horse horse : horses){ boolean isWin = horse.isWin(TOTAL); if(isWin){ service.shutdownNow(); //此处一定需要shutDownNow,否则线程不会被打断,会一直循环 //service.shutdown(); return; } } try { //休息两秒 TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } } private StringBuffer getHorseTrace(Horse horse) { StringBuffer trace = new StringBuffer(); for(int i = 0 ; i < horse.getStrides();i++){ trace.append("*"); } return trace; } @Override public void run() { getTrace(); } }
public class CyclicBarrierTest { public static void main(String[] ags){ ExecutorService service = Executors.newFixedThreadPool(10); //设置马的数量 int horseNum = 5; HorseRace race = new HorseRace(service); CyclicBarrier cyclicBarrier = new CyclicBarrier(horseNum,race); for(int i = 0;i < horseNum; i++){ Horse horse = new Horse("号-"+i,cyclicBarrier); race.addHorse(horse); service.execute(horse); } } }
执行结果:下图为正确运行结果末尾的一部分。
一共循环N遍,N不确定,与比赛的总长度TOTAL相关。

以下是实现过程遇到的问题:
1,如何实现CyclicBarrier的循环使用。
解决方法:await();线程中使用 while (!Thread.interrupted()){}
2,如何打断线程【关闭线程池】
解决方法:调用 executeService.shutDownNow();方法。
此处注意:只能使用.shutDownNow();调用.shutDown();方法并不会打断线程,会一直打印。
3,本程序运行结束后主线程也会结束,并不会存在任何线程存活。
4,当调用.shutDownNow();之后,其实Horse.的run();还会继续执行,并不是立刻停止的;
此处只是看似结束运行因为方法体都在while();之内,线程池关闭之后没有任何操作执行;
个人觉得此处while();条件为 !Thread.currentThread().isInterrupted();更加合适,因为此方法不会清除中断状态。
5,使用.shutDown();运行时,比赛没有结束时打印会间隔2s,但是一旦某一匹马完成了比赛,会继续循环打印,且打印没有时间间隔,迅速刷屏。
造成此现象的原因有待分析:
1,快速刷屏是因为一旦有马胜出就会调用return;执行不到sleep();
2,出现破坏栅栏的情况,如下图二所示。【原因未知,有待分析。】
错误运行结果如下图:
图一:

图二:
引申出的问题:
1,.shutDownNow();与.shutDown();的区别?分别的什么情况下使用。
2,本操作中Horse中的 strides 是否 可以使用vilatile修饰,放弃使用synchronized同步。
个人觉得不可以,因为操作 strides 时 strides += xxx;此操作并不是一个原子操作,并发会造成+ 数据的缺失。

浙公网安备 33010602011771号