CyclicBarrier

CyclicBarrier

此类可管理一组线程,当所有线程都到达"检查点"时执行特定的动作(Runnable),示例直接看其源码便好。

类图

和CountDownLatch类似,此类同样没有任何父类(除了Object)或是实现任何接口。

CyclicBarrier

await

整个类的核心便是此方法:

1public int await() {
2    return dowait(false, 0L);
3}

doWait方法简略版源码:

 1private int dowait(boolean timed, long nanos) {
 2    final ReentrantLock lock = this.lock;
 3    lock.lock();
 4    try {
 5        final Generation g = generation;
 6        // 未到达(检查点)数减一
 7        int index = --count;
 8         // 已达到检查点,执行给定的任务
 9        if (index == 0) {
10            boolean ranAction = false;
11            try {
12                final Runnable command = barrierCommand;
13                if (command != null)
14                    command.run();
15                ranAction = true;
16                nextGeneration();
17                return 0;
18            } finally {
19                if (!ranAction)
20                    breakBarrier();
21            }
22        }
23
24        // 尚有线程未到达检查点
25        for (;;) {
26            try {
27                 // 等待
28                if (!timed)
29                    trip.await();
30                else if (nanos > 0L)
31                    nanos = trip.awaitNanos(nanos);
32            } catch (InterruptedException ie) {
33                if (g == generation && ! g.broken) {
34                    breakBarrier();
35                    throw ie;
36                } else {
37                    Thread.currentThread().interrupt();
38                }
39            }
40
41            if (g.broken)
42                throw new BrokenBarrierException();
43
44            if (g != generation)
45                return index;
46
47            if (timed && nanos <= 0L) {
48                breakBarrier();
49                throw new TimeoutException();
50            }
51        }
52    } finally {
53        lock.unlock();
54    }
55}

一目了然,但是有一个疑问,当未到达数减为0时,已经阻塞的线程是在哪里唤醒的呢?

答案便是nextGeneration方法:

1private void nextGeneration() {
2    // signal completion of last generation
3    trip.signalAll();
4    // set up next generation
5    count = parties;
6    generation = new Generation();
7}