1 CyclicBarrier.Generation内部类
private static class Generation {
boolean broken = false;
}
2 CyclicBarrier
2.1 CyclicBarrier中的字段
(1)lock:执行breakBarrier方法和nextGeneration方法都需要获取该锁。
(2)trip:和lock绑定的Condition对象。
(3)parties:通过一个栅栏需要的线程数量。
(4)barrierCommand:在所有线程通过栅栏之前需要执行的任务。
(5)generation:一个generation代表一个栅栏。
(6)count:通过当前栅栏需要的线程数量。
private final ReentrantLock lock = new ReentrantLock();
private final Condition trip = lock.newCondition();
private final int parties;
private final Runnable barrierCommand;
private Generation generation = new Generation();
private int count;
2.2 CyclicBarrier中的构造方法
public CyclicBarrier(int parties, Runnable barrierAction) {
if (parties <= 0) throw new IllegalArgumentException();
this.parties = parties;
this.count = parties;
this.barrierCommand = barrierAction;
}
public CyclicBarrier(int parties) {
this(parties, null);
}
2.3 CyclicBarrier中的await方法
public int await() throws InterruptedException, BrokenBarrierException {
try {
return dowait(false, 0L);
} catch (TimeoutException toe) {
throw new Error(toe);
}
}
public int await(long timeout, TimeUnit unit)
throws InterruptedException,
BrokenBarrierException,
TimeoutException {
return dowait(true, unit.toNanos(timeout));
}
2.3.1 CyclicBarrier中的dowait方法
private int dowait(boolean timed, long nanos)
throws InterruptedException, BrokenBarrierException,
TimeoutException {
final ReentrantLock lock = this.lock;
lock.lock();
try {
final Generation g = generation;
if (g.broken)
throw new BrokenBarrierException();
if (Thread.interrupted()) {
breakBarrier();
throw new InterruptedException();
}
int index = --count;
if (index == 0) {
boolean ranAction = false;
try {
final Runnable command = barrierCommand;
if (command != null)
command.run();
ranAction = true;
nextGeneration();
return 0;
} finally {
// 如果执行barrierCommand中的run方法抛出异常
if (!ranAction)
// 打破栅栏
breakBarrier();
}
}
for (;;) {
try {
if (!timed)
trip.await();
else if (nanos > 0L)
nanos = trip.awaitNanos(nanos);
} catch (InterruptedException ie) {
// 运行到这里,说明其它线程调用了当前线程的interrupt方法
// 如果尚未更换栅栏并且尚未打破栅栏
if (g == generation && ! g.broken) {
// 打破栅栏
breakBarrier();
// 抛出异常
throw ie;
} else {
// 如果已经更换栅栏,恢复当前线程的中断状态
// 如果尚未更换栅栏并且已经打破栅栏,恢复当前线程的中断状态
Thread.currentThread().interrupt();
}
}
// 如果已经打破栅栏
if (g.broken)
// 抛出异常
throw new BrokenBarrierException();
// 如果已经更换栅栏
if (g != generation)
return index;
// 如果阻塞超时
if (timed && nanos <= 0L) {
// 打破栅栏
breakBarrier();
// 抛出异常
throw new TimeoutException();
}
}
} finally {
lock.unlock();
}
}
2.3.1.1 CyclicBarrier中的breakBarrier方法
// 打破栅栏
private void breakBarrier() {
generation.broken = true;
count = parties;
trip.signalAll();
}
2.3.1.2 CyclicBarrier中的nextGeneration方法
// 更换栅栏
private void nextGeneration() {
trip.signalAll();
count = parties;
generation = new Generation();
}
3 CountDownLatch和CyclicBarrier的主要区别
(1)CountDownLatch可以让一个或多个线程等待其它线程完成一些任务,再开始执行各自的任务;CyclicBarrier可以让多个线程相互等待,当所有线程到达之后,再开始执行各自的任务。
(2)CountDownLatch不能被重置,CyclicBarrier可以被重置。
(3)CountDownLatch利用共享锁实现,CyclicBarrier利用ReentrantLock+Condition实现。
4 CyclicBarrier使用案例
public class Test {
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(5, new Runnable() {
@Override
public void run() {
System.out.println("导游开始分发护照!!!");
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("导游分发了所有护照!!!");
}
});
ExecutorService executorService = Executors.newFixedThreadPool(5);
executorService.execute(new TravelTask(cyclicBarrier, "萨拉赫"));
executorService.execute(new TravelTask(cyclicBarrier, "马内"));
executorService.execute(new TravelTask(cyclicBarrier, "菲尔米诺"));
executorService.execute(new TravelTask(cyclicBarrier, "范迪克"));
executorService.execute(new TravelTask(cyclicBarrier, "阿利森"));
executorService.shutdown();
}
}
public class TravelTask implements Runnable {
private CyclicBarrier cyclicBarrier;
private String name;
public TravelTask(CyclicBarrier cyclicBarrier, String name) {
this.cyclicBarrier = cyclicBarrier;
this.name = name;
}
@Override
public void run() {
Random rand = new Random();
try {
TimeUnit.SECONDS.sleep(rand.nextInt(10) + 1);
System.out.println(name + "到达集合区域---");
cyclicBarrier.await();
System.out.println(name + "开始旅行啦...");
} catch (Exception e) {
e.printStackTrace();
}
}
}