Java并发工具类(栅栏CyclicBarrier)

并发工具类系列:java

Java并发工具类(闭锁CountDownLatch)bash

Java并发工具类(栅栏CyclicBarrier)markdown

Java并发工具类(信号量Semaphore)并发

CyclicBarrier适用于这样的状况:你但愿建立一组任务,它们并行地执行工做,而后在下一个步骤以前等待,直到全部任务都完成。栅栏和闭锁的关键区别在于,全部线程必须同时到达栅栏位置,才能继续执行。app

闭锁用于等待事件,而栅栏是线程之间彼此等待,等到都到的时候再决定作下一件事。能够参考Java并发工具类(闭锁CountDownLatch)dom

拿运动员的事情举例,运动员们跑到终点,互相等待全部人都到达终点后,再一块儿去作喝酒这件事。(运动员也许不能喝酒的,也许你们再跑一轮。)ide

下面用一个赛马程序来举例:工具

赛马

package concurrency;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.*;

class Horse implements Runnable {
    private static int counter = 0;
    private final int id = counter++;
    private int strides = 0;
    private static Random rand = new Random(47);
    private static CyclicBarrier barrier;
    public Horse(CyclicBarrier b) {barrier = b;}
    public synchronized int getStrides() {return strides;}
    public void run() {
        try {
            while (!Thread.interrupted()) {  //线程内不断循环
                synchronized (this) {
                    strides += rand.nextInt(3);   //每次马能够走0,1或者2步
                }
                barrier.await();  //走完后,就等全部其它马也走完,才能开始下一回合
            }
        } catch (InterruptedException e) {

        } catch (BrokenBarrierException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public String toString() {
        return "Horse " + id + " ";
    }

    public String tracks() {
        StringBuilder s =new StringBuilder();
        for(int i = 0; i < getStrides();i++)
            s.append("*");   //这里打印每一个马走的轨迹
        s.append(id);
        return s.toString();
    }
}
public class HorseRace {
    static final int FINISH_LINE = 75;
    private List<Horse> horses = new ArrayList<Horse>();
    private ExecutorService exec = Executors.newCachedThreadPool();
    private CyclicBarrier barrier;
    public HorseRace(int nHorses, final int pause) {
        barrier = new CyclicBarrier(nHorses, new Runnable() {
            @Override
            public void run() {
                StringBuilder s = new StringBuilder();
                for (int i = 0; i < FINISH_LINE; i++) {
                    s.append("="); //打印赛道
                }
                System.out.println(s);
                for (Horse horse : horses) {
                    System.out.println(horse.tracks());  //打印每匹马的轨迹
                }
                for (Horse horse : horses) {
                  if (horse.getStrides() >= FINISH_LINE) {
                      System.out.println(horse + "won!");   //每次检查,若是哪匹马到终点了,终止全部线程
                      exec.shutdownNow();
                      return;
                  }
                }
                try {
                    TimeUnit.MILLISECONDS.sleep(pause); //每走完一轮,暂停一小会输出
                } catch (InterruptedException e) {
                    System.out.println("barrier-action sleep interrupted");
                }
            }
        });

        for (int i = 0; i < nHorses; i++) {
            Horse horse = new Horse(barrier);
            horses.add(horse);
            exec.execute(horse);  //全部马的线程开始执行
        }
    }

    public static void main(String[] args) {
        int nHorses = 7;
        int pause = 200;
        new HorseRace(nHorses, pause);
    }
}
复制代码

咱们假设赛道长为75,马每次能走0,1或者2步,每次走完一轮后,互相等待。一旦全部马越过栅栏,它就会自动为下一回合的比赛作好准备。读者能够运行个人程序,在控制台上能够展现出必定的动画效果。post

上面的例子中,咱们向CyclicBarrier提供一个“栅栏动做”,它是一个Runnable,当计数值到达0时自动执行,这是CyclicBarrier和CountDownLatch之间的另外一个区别。动画

public CyclicBarrier(int parties, Runnable barrierAction)
复制代码

除此以外,CyclicBarrier还提供其余有用的方法,好比getNumberWaiting方法能够得到CyclicBarrier阻塞的线程数量。isBroken方法用来知道阻塞的线程是否被中断。好比如下代码执行完以后会返回true。

相关文章
相关标签/搜索