一、核心代码阅读
await()方法调用的是dowait
/*
**长循环等待
**
*/
private int dowait(boolean timed, long nanos)
throws InterruptedException, BrokenBarrierException,TimeoutException {
final ReentrantLock lock = this.lock;
//获取独占锁
lock.lock();
try {
//将换代信息赋值给变量g
final Generation g = generation;
//如果栅栏损坏,则抛出异常(什么情况会导致栅栏损坏?)
if (g.broken)
throw new BrokenBarrierException();
//如果一个线程的中断标志是True,那么立即损坏栅栏,直接抛出异常
if (Thread.interrupted()) {
breakBarrier();
throw new InterruptedException();
}
//当有线程调用barrier.await方法时,计数器都减1
int index = --count;
//最后一个线程调用barrier.await时,计数器减1后变为0
if (index == 0) { // tripped
boolean ranAction = false;
try {
//如果创建栅栏时,指定了屏障任务,则最后到达栅栏的线程执行屏障任务
final Runnable command = barrierCommand;
if (command != null)
command.run();
ranAction = true;
//更新换代处理(先通过Condition唤醒其他线程,然后重置Generation)
//最后的线程不需要进入等待状态,会接着执行自己的任务
nextGeneration();
return 0;
} finally {
//[异常处理]如果执行屏障任务出错,则忽略异常,并且损坏栅栏
if (!ranAction)
breakBarrier();
}
}
// loop until tripped, broken, interrupted, or timed out
for (;;) {
try {
if (!timed)
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 {
//释放独占锁
lock.unlock();
}
二、总结
2.1 try{ block1 }finally { block2 }, 可以看出finally中并没有return语句,也就是说此方法的返回值是block1中的return返回的值。
2.2 为什么此方法需要用ReentrantLock把过程锁住呢?
2.3 for循环是怎么退出的?如果一直循环下去,那么锁是怎么释放掉的?
2.4 await方法逻辑如下,除非发生一下几种情况,否则线程一直处于等待状态。
a 当前线程被其他线程中断。
b 其他的某一个线程中断了处于等待状态的某一线程。
c 最后一个线程到达栅栏。
d 最后一个线程到达栅栏后,执行屏障任务发生异常。
e 超时等待,某一线程等待的时间超过设置时间。
f 某一线程等待barrier超时。
g 栅栏被重置reset。reset方法用户将栅栏重置为初始状态。
三、使用说明
比如说某一团队小组开会,全部成员都到齐后,会议还需要组长到后,才能开始。在组长没有到来之前,小组成员都是相互等待的状态。