**特性:**可重用 ,恢复初始状态有两种方式 ,一种是直接调用reset方法,一种是await通过后内部会自动重置
结构:
- 一个栅栏状态记录器Generation,记录栅栏是否被破坏
- 一个全局锁ReentrantLock对象
- 一个全局锁绑定的通信器Condition对象
- 一个上限线程数parties
- 一个回调接口Runnable对象barrierCommand
- 一个计数器count
栅栏原理:
- 初始化一个CyclicBarrier对象,构造器中需要包含parties与一个Runnable回调 ,回调可以为空
- 每次调用CyclicBarrier对象的await方法,内部调用了直接dowait方法
- 获取全局锁
- count减一
- count结果为0 -> barrierCommand不为空则直接调用起run方法 -> 发送信号通知其他线程 -> count恢复为parties并且创建一个新状态记录器,若是中间出现异常则直接设置栅栏为破坏状态
- count不为0 -> 调用lock锁的的await方法进行等待 ,收到通知后发现状态记录器已经更新则安全通过,若是发生线程中断也设置栅栏为破坏状态并继续抛异常
应用示例
public class Demo {
public static void main(String[] args) {
CyclicBarrier cy = new CyclicBarrier(2, ()-> {
System.out.println("+++++++栅栏冲破");
});
for(int i =0; i < 10;i++) {
int t = i;
new Thread(()->{
try {
Thread.sleep(1000 * t);
System.out.println("线程" + t +"到达");
cy.await();
System.out.println("线程" + t +"冲过");
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
}).start();
}
}
}
运行结果:
线程0到达
线程1到达
+++++++栅栏冲破
线程1冲过
线程0冲过
线程2到达
线程3到达
+++++++栅栏冲破
线程3冲过
线程2冲过
线程4到达
线程5到达
+++++++栅栏冲破
线程5冲过
线程4冲过
线程6到达
线程7到达
+++++++栅栏冲破
线程7冲过
线程6冲过
线程8到达
线程9到达
+++++++栅栏冲破
线程9冲过
线程8冲过
成员变量
//全局锁
private final ReentrantLock lock = new ReentrantLock();
/** 通知队列 */
private final Condition trip = lock.newCondition();
/** 线程数目统计 */
private final int parties;
/*冲破栅栏的回调线程*/
private final Runnable barrierCommand;
/** The current generation */
private Generation generation = new Generation();
//累计数 每次调用await就减1 重置后恢复parties
private int count;
构造方法:
public CyclicBarrier(int parties)
/**
* parties 线程数量
* barrierAction 线程冲破后的回调
*/
public CyclicBarrier(int parties, Runnable barrierAction)
主要方法
await
public int await() throws InterruptedException, BrokenBarrierException {
try {
return dowait(false, 0L);
} catch (TimeoutException toe) {
throw new Error(toe); // cannot happen;
}
}
awai方法内部直接调用的是dowait,超时后直接抛出Error。
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;
//累计数count减到0 标识栅栏前的线程数目已经达到上限 可以放行了
if (index == 0) { // tripped
boolean ranAction = false;
try {
final Runnable command = barrierCommand;
if (command != null)
//发现回调类 直接调用run方法,使用当前线程执行
command.run();
ranAction = true;
//回调检查并执行完毕后通知栅栏前其他等待的线程可以继续执行了
nextGeneration();
return 0;
} finally {
if (!ranAction)
breakBarrier();
}
}
// loop until tripped, broken, interrupted, or timed out
for (;;) {
try {
//没有设置超时时间直接调用 ReentrantLock 的await方法
if (!timed)
trip.await();
//设置了超时时间后调用ReentrantLock 的await(time)方法
else if (nanos > 0L)
nanos = trip.awaitNanos(nanos);
} catch (InterruptedException ie) {
//发生中断异常后 若当前栅栏状态不是破坏状态则直接设置为破坏状态 再继续外抛异常
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();
}
}
await()方法会阻塞当前线程,直到运行到此处的方法达到上限,需要注意的是该方法可能会抛出多种异常,并且抛出后仅影响当前线程,不影响CyclicBarrier继续使用,但若是线程是有状态的,例如线程总数刚好够用,那么除去抛出异常的线程数后总数可能就不够了,可能会造成整体死掉