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;此操作并不是一个原子操作,并发会造成+ 数据的缺失。

  

 

posted @ 2022-01-24 14:14  豆浆不要糖  阅读(27)  评论(0)    收藏  举报