概述
CyclicBarrier和CountDownLatch简直不要太像,CountDownLatch事件只能触发一次,而CyclicBarrier可以多次循环使用,作用是类似的,都是等所有的线程都执行完,再去执行特定的任务,但CyclicBarrier功能比CountDownLatch强大,CyclicBarrier是一组线程相互等待,发生阻塞,直到最后一个线程执行完,再打开屏障,被阻塞的线程继续执行。
使用
方法解释
public CyclicBarrier(int parties) {
this(parties, null);
}
构造方法,parties:参与等待的线程数,小于1会报IllegalArgumentException。
public CyclicBarrier(int parties, Runnable barrierAction) {
if (parties <= 0) throw new IllegalArgumentException();
this.parties = parties;
this.count = parties;
this.barrierCommand = barrierAction;
}
构造方法,parties:参与的线程数,小于1会报IllegalArgumentException;barrierAction:最后需要执行的任务。
public int await() throws InterruptedException, BrokenBarrierException {
try {
return dowait(false, 0L);
} catch (TimeoutException toe) {
throw new Error(toe); // cannot happen
}
}
屏障点,线程执行到该方法进入阻塞状态。
public int await(long timeout, TimeUnit unit)
throws InterruptedException,
BrokenBarrierException,
TimeoutException {
return dowait(true, unit.toNanos(timeout));
}
屏障点,线程执行该方法一定时间内进入阻塞状态。
private void breakBarrier() {
generation.broken = true;
count = parties;
trip.signalAll();
}
只能在持有锁的时候调用,破坏屏障唤醒所有线程。
public boolean isBroken() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return generation.broken;
} finally {
lock.unlock();
}
}
检查屏障是否被破坏,等待线程被中断或者超时都是为屏障破坏。
public void reset() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
breakBarrier(); // break the current generation
nextGeneration(); // start a new generation
} finally {
lock.unlock();
}
}
重置屏障,回到初始屏障未被破坏的状态。
使用
public class Programmer extends Thread {
private CyclicBarrier cyclicBarrier;
private int index;
public Programmer(CyclicBarrier cyclicBarrier, int index) {
this.cyclicBarrier = cyclicBarrier;
this.index = index;
}
void work() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("程序员" + index + "活干完了");
}
void prepare() {
System.out.println("程序员" + index + "准备好了");
}
@Override
public void run() {
try {
// 准备工作
prepare();
cyclicBarrier.await();
// 干活
work();
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(5,()-> System.out.println("下一步"));
for (int i = 0; i < 5; i++) {
new Programmer(cyclicBarrier, i).start();
}
}
}
结果:
程序员1准备好了
程序员0准备好了
程序员3准备好了
程序员2准备好了
程序员4准备好了
下一步
程序员4活干完了
程序员3活干完了
程序员0活干完了
程序员2活干完了
程序员1活干完了
下一步
5个线程,等5个线程都把同样的工作做完后才进行下一步。但凡5个线程中有一个破坏了规矩,比如:等待超时、唤醒等待线程,所有线程都会被唤醒,cyclicBarrier功能失效。