并发工具类系列:java
Java并发工具类(闭锁CountDownLatch)bash
CyclicBarrier适用于这样的状况:你但愿建立一组任务,它们并行地执行工做,而后在下一个步骤以前等待,直到全部任务都完成。栅栏和闭锁的关键区别在于,全部线程必须同时到达栅栏位置,才能继续执行。dom
闭锁用于等待事件,而栅栏是线程之间彼此等待,等到都到的时候再决定作下一件事。能够参考Java并发工具类(闭锁CountDownLatch)ide
拿运动员的事情举例,运动员们跑到终点,互相等待全部人都到达终点后,再一块儿去作喝酒这件事。(运动员也许不能喝酒的,也许你们再跑一轮。)工具
下面用一个赛马程序来举例:post
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步,每次走完一轮后,互相等待。一旦全部马越过栅栏,它就会自动为下一回合的比赛作好准备。读者能够运行个人程序,在控制台上能够展现出必定的动画效果。动画
上面的例子中,咱们向CyclicBarrier提供一个“栅栏动做”,它是一个Runnable,当计数值到达0时自动执行,这是CyclicBarrier和CountDownLatch之间的另外一个区别。ui
public CyclicBarrier(int parties, Runnable barrierAction)
复制代码
除此以外,CyclicBarrier还提供其余有用的方法,好比getNumberWaiting方法能够得到CyclicBarrier阻塞的线程数量。isBroken方法用来知道阻塞的线程是否被中断。好比如下代码执行完以后会返回true。