并发工具类系列:java
Java并发工具类(闭锁CountDownLatch)bash
Java并发工具类(栅栏CyclicBarrier)markdown
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。