源码阅读 - java.util.concurrent (四)CyclicBarrier
CyclicBarrier是一个用于线程同步的辅助类,它允许一组线程等待彼此,直到所有线程都到达集合点,然后执行某个设定的任务。
举个例子:几个人约定了某个地方集中,然后一起出发去旅行。每个参与的人就是一个线程,CyclicBarrier就是那个集合点,所有人到了之后,就一起出发。
CyclicBarrier的构造函数有两个:
1 // parties是参与等待的线程的数量,barrierAction是所有线程达到集合点之后要做的动作 2 public CyclicBarrier(int parties, Runnable barrierAction); 3 4 // 达到集合点之后不执行操作的构造函数 5 public CyclicBarrier(int parties)
CyclicBarrier只是记录线程的数目,CyclicBarrier是不创建任何线程的。线程是通过调用CyclicBarrier的await方法来等待其他线程,如果调用await方法的线程数目达到了预设值,也就是上面构造方法中的parties,CyclicBarrier就会开始执行barrierAction。
因此我们来看CyclicBarrier的核心方法dowait,也就是await方法调用的私有方法:
1 private int dowait(boolean timed, long nanos) 2 throws InterruptedException, BrokenBarrierException, 3 TimeoutException { 4 final ReentrantLock lock = this.lock; 5 lock.lock(); 6 try { 7 final Generation g = generation; 8 9 if (g.broken) 10 throw new BrokenBarrierException(); 11 12 if (Thread.interrupted()) { 13 breakBarrier(); 14 throw new InterruptedException(); 15 } 16 // count就是预设的parties,count减1的值表示还剩余几个 17 // 线程没有达到该集合点 18 int index = --count; 19 // index为0表示所有的线程都已经达到集合点,这时 20 // 占用最后一个线程,执行运行设定的任务 21 if (index == 0) { 22 boolean ranAction = false; 23 try { 24 final Runnable command = barrierCommand; 25 if (command != null) 26 command.run(); 27 ranAction = true; 28 // 唤醒其他等待的线程, 29 // 更新generation以便下一次运行 30 nextGeneration(); 31 return 0; 32 } finally { 33 // 如果运行任务时发生异常,设置状态为broken 34 // 并且唤醒其他等待的线程 35 if (!ranAction) 36 breakBarrier(); 37 } 38 } 39 40 // 还有线程没有调用await,进入循环等待直到其他线程 41 // 达到集合点或者等待超时 42 for (;;) { 43 try { 44 // 如果没有设置超时,进行无超时的等待 45 if (!timed) 46 trip.await(); 47 // 有超时设置,进行有超时的等待 48 else if (nanos > 0L) 49 nanos = trip.awaitNanos(nanos); 50 } catch (InterruptedException ie) { 51 // generation如果没有被更新表示还是当前的运行 52 // (generation被更新表示集合完毕并且任务成功), 53 // 在状态没有被设置为broken状态的情况下,遇到线程 54 // 中断异常表示当前线程等待失败,需要设置为broken 55 // 状态,并且抛出中断异常 56 if (g == generation && ! g.broken) { 57 breakBarrier(); 58 throw ie; 59 } else { 60 // else对应的条件为:g != generation || g.broken 61 // 表示要么generation已经被更新意味着所有线程已经到达 62 // 集合点并且任务执行成功,要么就是是broken状态意味着 63 // 任务执行失败,无论哪种情况所有线程已经达到集合点,当 64 // 前线程要结束等待了,发生了中断异常,需要中断当前线程 65 // 表示遇到了中断异常。 66 Thread.currentThread().interrupt(); 67 } 68 } 69 70 // 如果发现当前状态为broken,抛出异常 71 if (g.broken) 72 throw new BrokenBarrierException(); 73 // generation被更新表示所有线程都已经达到集合点 74 // 并且预设任务已经完成,返回该线程进入等待顺序号 75 if (g != generation) 76 return index; 77 // 等待超时,设置为broken状态并且抛出超时异常 78 if (timed && nanos <= 0L) { 79 breakBarrier(); 80 throw new TimeoutException(); 81 } 82 } 83 } finally { 84 lock.unlock(); 85 } 86 }
1. 任何一个线程等待时发生异常,CyclicBarrier都将被设置为broken状态,运行都会失败
2. 每次运行成功之后CyclicBarrier都会清理运行状态,这样CyclicBarrier可以重新使用
3. 对于设置了超时的等待,在发生超时的时候会引起CyclicBarrier的broken