java并发编程之美 学习笔记
CyclicBarrier
CyclicBarrier(回环屏障
),它可以让一组线程全部达到一个状态后,再全部同时执行
。
这里之所以叫作回环是因为当所有等待线程执行完毕,并重置CyclicBarrier的状态后它可以被重用
。
demo
场景:旅行团有两个人A和B, 旅行路线中有1,2,3三个站点, 必须所有人到达站点时,才可以向下一个站点触发.
public class CyclicBarrierTest {
private static CyclicBarrier cyclicBarrier = new CyclicBarrier(2);
public static void main(String[] args) {
ExecutorService executorService = new ThreadPoolExecutor(2, 2, 0l, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
executorService.submit(() -> {
try {
System.out.println("A arrived ----- Step1");
cyclicBarrier.await();
System.out.println("A arrived ----- Step2");
cyclicBarrier.await();
System.out.println("A arrived ----- Step3");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
});
executorService.submit(() -> {
try {
System.out.println("B arrived ----- Step1");
//B to buy something ...
Thread.sleep(30);
cyclicBarrier.await();
System.out.println("B arrived ----- Step2");
//B to pee...
Thread.sleep(70);
cyclicBarrier.await();
System.out.println("B arrived ----- Step3");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
});
executorService.shutdown();
}
}
执行结果:
源码分析
结构
CyclicBarrier内部是基于独占锁
实现的,本质上还是基于AQS
锁实现。
public class CyclicBarrier {
//记录线程数: 当parties个线程调用await()后,所有的线程会会冲破屏障,向后执行
private final int parties;
//初始值为parties
//每当一个线程执行await()后,count--,当count == 0时表示所有线程到达屏障点,继而向后执行
private int count;
//当所有线程到达某一个屏障点时执行。
private final Runnable barrierCommand;
private static class Generation {
//记录屏障是否被打破 --- 并未申明为volatile,因为它是在lock()内部使用的,所以无需什么
boolean broken = false;
}
//独占锁
private final ReentrantLock lock = new ReentrantLock();
//Condition等待屏障被打破
private final Condition trip = lock.newCondition();
//当到达下一个屏障点时,generation 会重新new
private Generation generation = new Generation();
}
初始化
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);
}
为什么会同时定义parties ,count 两个属性来记录线程数呢?
因为当count-- 到0时,会重新将parties 赋值给count,从而重复使用
.
await()
public int await() throws InterruptedException, BrokenBarrierException {
try {
return dowait(false, 0L);
} catch (TimeoutException toe) {
throw new Error(toe); // cannot happen
}
}
//带有超时时间的await()
public int await(long timeout, TimeUnit unit)
throws InterruptedException,
BrokenBarrierException,
TimeoutException {
return dowait(true, unit.toNanos(timeout));
}
await()
的执行逻辑,最终还是委托给dowait()
来实现的。
dowait()
/**
* @param timed 是否配置超时时间
* @param nanos 超时时间,单位为nanos
*/
private int dowait(boolean timed, long nanos)
throws InterruptedException, BrokenBarrierException,
TimeoutException {
final ReentrantLock lock = this.lock;
//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) { //当index == 0, 表示所有线程到达屏障点
boolean ranAction = false;
try {
final Runnable command = barrierCommand;
if (command != null)
command.run(); //执行初始化的barrierCommand
ranAction = true;
//激活执行await()而阻塞的线程,并重置count,和new Generation()
nextGeneration();
//返回 0
return 0;
} finally {
if (!ranAction)
//如果ranAction ==false
//breakBarrier(): 激活执行await()而阻塞的线程,并重置count, 设置generation为broken
//与nextGeneration()的区别为::: 设置:generation.broken = true;
breakBarrier();
}
}
//index != 0
// 循环直到: tripped, broken, interrupted, or timed out 等事件发生;
for (;;) {
try {
if (!timed)
//等待trip.singal()或者singalAll()触发
trip.await();
else if (nanos > 0L)
//带有超时时间的等待
nanos = trip.awaitNanos(nanos);
} catch (InterruptedException ie) {
if (g == generation && ! g.broken) {
breakBarrier();
throw ie;
} else {
// We're about to finish waiting even if we had not
// been interrupted, so this interrupt is deemed to
// "belong" to subsequent execution.
Thread.currentThread().interrupt();
}
}
if (g.broken)
throw new BrokenBarrierException();
if (g != generation)
return index;
if (timed && nanos <= 0L) {
breakBarrier();
throw new TimeoutException();
}
}
} finally {
//unlock
lock.unlock();
}
}
nextGeneration()
当正常打破屏障点时,执行nextGeneration()
.
private void nextGeneration() {
//激活执行await()而阻塞的线程
trip.signalAll();
//重置count
count = parties;
//new Generation()
generation = new Generation();
}
breakBarrier()
当非
正常打破屏障点时,执行breakBarrier()
.
private void breakBarrier() {
//设置broken为true
generation.broken = true;
count = parties;//重置count
trip.signalAll(); //激活执行await()而阻塞的线程
}