/* * CyclicBarrier源码解读,若要转载,请注明出处! */ package java.util.concurrent; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; /** * * @author 赵泉伟 */ public class CyclicBarrier { /** * Each use of the barrier is represented as a generation instance. * The generation changes whenever the barrier is tripped, or * is reset. There can be many generations associated with threads * using the barrier - due to the non-deterministic way the lock * may be allocated to waiting threads - but only one of these * can be active at a time (the one to which {@code count} applies) * and all the rest are either broken or tripped. * There need not be an active generation if there has been a break * but no subsequent reset. */ private static class Generation {//静态内部类 boolean broken = false; } /** The lock for guarding barrier entry */ private final ReentrantLock lock = new ReentrantLock();//可重入锁 /** Condition to wait on until tripped */ private final Condition trip = lock.newCondition();//等待条件 /** The number of parties */ private final int parties;//请求的线程数 /* The command to run when tripped */ private final Runnable barrierCommand;//可选的需执行的Runnable对象 /** The current generation */ private Generation generation = new Generation();//Generation对象 /** * Number of parties still waiting. Counts down from parties to 0 * on each generation. It is reset to parties on each new * generation or when broken. */ private int count;//计数器 /** * Updates state on barrier trip and wakes up everyone. * Called only while holding lock. */ private void nextGeneration() {//创建Generation对象 // signal completion of last generation trip.signalAll();//唤醒所有线程 // set up next generation count = parties;//重置计数器,默认为原始线程总数 generation = new Generation();//创建Generation对象 } /** * Sets current barrier generation as broken and wakes up everyone. * Called only while holding lock. */ private void breakBarrier() {//破损模式 generation.broken = true;//置为true count = parties;//重置计数器,默认为原始线程总数 trip.signalAll();//唤醒所有线程 } /** * Main barrier code, covering the various policies. */ private int dowait(boolean timed, long nanos)//执行阻塞方法 throws InterruptedException, BrokenBarrierException, TimeoutException { final ReentrantLock lock = this.lock;//获取可重入锁对象 lock.lock();//加锁 try { final Generation g = generation;//获取Generation对象 if (g.broken)//如果破损状态是true throw new BrokenBarrierException();//则抛异常 if (Thread.interrupted()) {//如果当前线程被中断过 breakBarrier();//调用破损模式方法 throw new InterruptedException();//并抛异常 } int index = --count;//计数器自减 if (index == 0) { // 如果计数器为0表示是最后一个线程 boolean ranAction = false;//Bool类型的标志位 try { final Runnable command = barrierCommand;//获取构造器传入的Runnable对象 if (command != null)//如果对象不是空 command.run();//则调用run方法执行 ranAction = true;//置为true nextGeneration();//重置计数器并唤醒所有线程 return 0;//返回0 } finally { if (!ranAction)//如果发生了异常则标志位为false breakBarrier();//调用破损模式进行重置 } } // loop until tripped, broken, interrupted, or timed out for (;;) {//自旋 try { if (!timed)//如果没有设置超时,则直接阻塞 trip.await();//则调用阻塞方法 else if (nanos > 0L)//如果超时时间>0 nanos = trip.awaitNanos(nanos);//调用带超时时间的阻塞方法 } catch (InterruptedException ie) {//捕捉打断异常 if (g == generation && ! g.broken) {//如果是当前的generation对象并且没有破损 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)//如果generation不是当前的generation对象 return index;//则返回当前的索引值 if (timed && nanos <= 0L) {//如果是超时模式但是超时时间<=0 breakBarrier();//则调用破损模式 throw new TimeoutException();//抛出超时异常 } } } finally { lock.unlock();//始终要解锁 } } /** * Creates a new {@code CyclicBarrier} that will trip when the * given number of parties (threads) are waiting upon it, and which * will execute the given barrier action when the barrier is tripped, * performed by the last thread entering the barrier. * * @param parties the number of threads that must invoke {@link #await} * before the barrier is tripped * @param barrierAction the command to execute when the barrier is * tripped, or {@code null} if there is no action * @throws IllegalArgumentException if {@code parties} is less than 1 */ public CyclicBarrier(int parties, Runnable barrierAction) {//带原始线程数量和Runnable对象的构造器 if (parties <= 0) throw new IllegalArgumentException();//如果线程数量<=0则抛出异常 this.parties = parties;//为parties赋值 this.count = parties;//计数器count默认为parties this.barrierCommand = barrierAction;//为Runnable对象赋值 } /** * Creates a new {@code CyclicBarrier} that will trip when the * given number of parties (threads) are waiting upon it, and * does not perform a predefined action when the barrier is tripped. * * @param parties the number of threads that must invoke {@link #await} * before the barrier is tripped * @throws IllegalArgumentException if {@code parties} is less than 1 */ public CyclicBarrier(int parties) {//带原始线程数量的构造器 this(parties, null);//调用构造器初始化 } /** * Returns the number of parties required to trip this barrier. * * @return the number of parties required to trip this barrier */ public int getParties() {//获取当前线程数量 return parties;//返回 } /** * Waits until all {@linkplain #getParties parties} have invoked * {@code await} on this barrier. * * <p>If the current thread is not the last to arrive then it is * disabled for thread scheduling purposes and lies dormant until * one of the following things happens: * <ul> * <li>The last thread arrives; or * <li>Some other thread {@linkplain Thread#interrupt interrupts} * the current thread; or * <li>Some other thread {@linkplain Thread#interrupt interrupts} * one of the other waiting threads; or * <li>Some other thread times out while waiting for barrier; or * <li>Some other thread invokes {@link #reset} on this barrier. * </ul> * * <p>If the current thread: * <ul> * <li>has its interrupted status set on entry to this method; or * <li>is {@linkplain Thread#interrupt interrupted} while waiting * </ul> * then {@link InterruptedException} is thrown and the current thread's * interrupted status is cleared. * * <p>If the barrier is {@link #reset} while any thread is waiting, * or if the barrier {@linkplain #isBroken is broken} when * {@code await} is invoked, or while any thread is waiting, then * {@link BrokenBarrierException} is thrown. * * <p>If any thread is {@linkplain Thread#interrupt interrupted} while waiting, * then all other waiting threads will throw * {@link BrokenBarrierException} and the barrier is placed in the broken * state. * * <p>If the current thread is the last thread to arrive, and a * non-null barrier action was supplied in the constructor, then the * current thread runs the action before allowing the other threads to * continue. * If an exception occurs during the barrier action then that exception * will be propagated in the current thread and the barrier is placed in * the broken state. * * @return the arrival index of the current thread, where index * {@code getParties() - 1} indicates the first * to arrive and zero indicates the last to arrive * @throws InterruptedException if the current thread was interrupted * while waiting * @throws BrokenBarrierException if <em>another</em> thread was * interrupted or timed out while the current thread was * waiting, or the barrier was reset, or the barrier was * broken when {@code await} was called, or the barrier * action (if present) failed due to an exception */ public int await() throws InterruptedException, BrokenBarrierException {//阻塞方法 try { return dowait(false, 0L);//调用阻塞方法 ,超时默认默认为false,超时时间默认为0 } catch (TimeoutException toe) {//捕捉超时异常 throw new Error(toe); // 抛出Error类型异常 } } /** * Waits until all {@linkplain #getParties parties} have invoked * {@code await} on this barrier, or the specified waiting time elapses. * * <p>If the current thread is not the last to arrive then it is * disabled for thread scheduling purposes and lies dormant until * one of the following things happens: * <ul> * <li>The last thread arrives; or * <li>The specified timeout elapses; or * <li>Some other thread {@linkplain Thread#interrupt interrupts} * the current thread; or * <li>Some other thread {@linkplain Thread#interrupt interrupts} * one of the other waiting threads; or * <li>Some other thread times out while waiting for barrier; or * <li>Some other thread invokes {@link #reset} on this barrier. * </ul> * * <p>If the current thread: * <ul> * <li>has its interrupted status set on entry to this method; or * <li>is {@linkplain Thread#interrupt interrupted} while waiting * </ul> * then {@link InterruptedException} is thrown and the current thread's * interrupted status is cleared. * * <p>If the specified waiting time elapses then {@link TimeoutException} * is thrown. If the time is less than or equal to zero, the * method will not wait at all. * * <p>If the barrier is {@link #reset} while any thread is waiting, * or if the barrier {@linkplain #isBroken is broken} when * {@code await} is invoked, or while any thread is waiting, then * {@link BrokenBarrierException} is thrown. * * <p>If any thread is {@linkplain Thread#interrupt interrupted} while * waiting, then all other waiting threads will throw {@link * BrokenBarrierException} and the barrier is placed in the broken * state. * * <p>If the current thread is the last thread to arrive, and a * non-null barrier action was supplied in the constructor, then the * current thread runs the action before allowing the other threads to * continue. * If an exception occurs during the barrier action then that exception * will be propagated in the current thread and the barrier is placed in * the broken state. * * @param timeout the time to wait for the barrier * @param unit the time unit of the timeout parameter * @return the arrival index of the current thread, where index * {@code getParties() - 1} indicates the first * to arrive and zero indicates the last to arrive * @throws InterruptedException if the current thread was interrupted * while waiting * @throws TimeoutException if the specified timeout elapses. * In this case the barrier will be broken. * @throws BrokenBarrierException if <em>another</em> thread was * interrupted or timed out while the current thread was * waiting, or the barrier was reset, or the barrier was broken * when {@code await} was called, or the barrier action (if * present) failed due to an exception */ public int await(long timeout, TimeUnit unit)//带超时时间的阻塞 throws InterruptedException, BrokenBarrierException, TimeoutException { return dowait(true, unit.toNanos(timeout));//调用阻塞方法,超时状态为true,传入对应的超时时间 } /** * Queries if this barrier is in a broken state. * * @return {@code true} if one or more parties broke out of this * barrier due to interruption or timeout since * construction or the last reset, or a barrier action * failed due to an exception; {@code false} otherwise. */ public boolean isBroken() {//是否破损 final ReentrantLock lock = this.lock;//获取可重入锁 lock.lock();//加锁 try { return generation.broken;//返回破损状态 } finally { lock.unlock();//始终要释放锁 } } /** * Resets the barrier to its initial state. If any parties are * currently waiting at the barrier, they will return with a * {@link BrokenBarrierException}. Note that resets <em>after</em> * a breakage has occurred for other reasons can be complicated to * carry out; threads need to re-synchronize in some other way, * and choose one to perform the reset. It may be preferable to * instead create a new barrier for subsequent use. */ public void reset() {//重置 final ReentrantLock lock = this.lock;//获取可重入锁 lock.lock();//加锁 try { breakBarrier(); // 调用破损模式方法 nextGeneration(); // 调用重置方法并且创建Generation对象 } finally { lock.unlock();//始终要解锁 } } /** * Returns the number of parties currently waiting at the barrier. * This method is primarily useful for debugging and assertions. * * @return the number of parties currently blocked in {@link #await} */ public int getNumberWaiting() {//获取当前处于阻塞状态的线程 final ReentrantLock lock = this.lock;//获取可重入锁 lock.lock();//加锁 try { return parties - count;//用原始线程的数量-未阻塞线程的数量=已阻塞线程的数量 } finally { lock.unlock();//始终要解锁 } } }
CyclicBarrier源码解读,若要转载请注明出处
最新推荐文章于 2022-08-08 22:22:22 发布