[JDK] JDK source code analysis -CyclicBarrier

Outline

 

CyclicBarrier and contracting is a tool in class, it's a typical application scenario: several threads after performing the task, execute another thread (callback function, optional), and then continue to the next round, and so forth.

 

Make a popular example, can be likened to CyclicBarrier execution flow: a few people (analogy thread) laps around the playground, everyone reach the end (the end understood as "barrier (barrier)", there may be arriving order has corresponding thread execution speed tasks), perform an action (callback function), and then continue to cycle (next run the next lap), and so forth.

 

Compared with such a CountDownLatch, which can be understood as "disposable (one-shot)" operation, while the former is "loop" operation, which code for the following analysis.

 

Code Analysis

 

CyclicBarrier main methods are as follows:

Which is commonly used in two await method, is to let the current thread into a wait state.

 

Member variables and nested categories:

// 内部嵌套类
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;

/** The current generation */
private Generation generation = new 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;

Generation represents the inner nested algebraic class, each barrier (Barrier) belong to the same generation of damage before, after entering the next generation.

 

Constructor

// 无回调函数
public CyclicBarrier(int parties) {
    this(parties, null);
}

// 有回调函数
public CyclicBarrier(int parties, Runnable barrierAction) {
    if (parties <= 0) throw new IllegalArgumentException();
    this.parties = parties;
    this.count = parties;
    this.barrierCommand = barrierAction;
}

CyclicBarrier have two constructors, the latter of which can be passed a callback function (barrierAction), parties represents await the calling thread.

 

await method

// 阻塞式等待
public int await() throws InterruptedException, BrokenBarrierException {
    try {
        return dowait(false, 0L);
    } catch (TimeoutException toe) {
        throw new Error(toe); // cannot happen
    }
}

// 有超时的等待
public int await(long timeout, TimeUnit unit)
    throws InterruptedException,
           BrokenBarrierException,
           TimeoutException {
    return dowait(true, unit.toNanos(timeout));
}

We can see (which is also the core methods CyclicBarrier of) two methods are invoked await dowait method to achieve, as follows:

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();
        } 

        // COUNT Save. 1 
        int index = - COUNT;
         IF (index == 0) {   // TRIPPED
             // operation triggered when COUNT is reduced to 0 
            Boolean ranAction = to false ;
             the try {
                 // the passed callback 
                Final the Runnable = the Command barrierCommand;
                 IF (the Command =! null )
                     // If passed callback function, the callback function executes
                     // PS: it can be seen, the callback function executed by the end of the last thread execution 
                    command.run (); 
                ranAction =to true );
                 // into the next generation (next operation) 
                NextGeneration ();
                 return 0 ; 
            } the finally {
                 IF (! RanAction) 
                    breakBarrier (); 
            } 
        } 

        // Loop an until TRIPPED, Broken, interrupted, or Timed OUT 
        for (;; ) {
             the try {
                 // when 0 count is not, the current thread enters a wait state 
                IF (! Timed) 
                    trip.await (); 
                the else  IF (of nanos> 0L 
                    of 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();
    }
}

nextGeneration 和 breakBarrier:

// 进入下一轮
private void nextGeneration() {
    // signal completion of last generation
    trip.signalAll();
    // set up next generation
    count = parties;
    generation = new Generation();
}

// 破坏屏障
private void breakBarrier() {
    generation.broken = true;
    count = parties;
    trip.signalAll();
}

Execution process: the same parties and initialization count value (parameter passed by the constructor parties), after every one thread invoked await count value is decremented by 1 until the count is zero (0 if not waiting), performed incoming callback function barrierCommand (if not empty), and then wake up all the threads, and resets the count for the parties, to start the next round of action.

 

For example scenario

 

To facilitate understanding CyclicBarrier usage, the following example demonstrates a simple (for reference only):

public  class CyclicBarrierTest {
   Private  static  Final  int COUNT =. 3 ; 

  public  static  void main (String [] args) throws InterruptedException {
     // Initialization and callback objects CyclicBarrier 
    CyclicBarrier CyclicBarrier = new new CyclicBarrier (COUNT, () -> {
       // analog callback manipulation functions (analog write) 
      System.out.println (Thread.currentThread () getName () + "Start .. writing." );
       the try { 
        TimeUnit.SECONDS.sleep ( . 1 ); 
      } the catch (InterruptedException E) {
        e.printStackTrace (); 
      } 
      System.out.println ( "---------" ); 
    }); 

    the while ( to true ) {
       // create several threads to perform tasks 
      for ( int I = 0; I <COUNT; I ++ ) {
         new new the Thread (() -> {
           // analog read 
          System.out.println (Thread.currentThread () getName () + "IS reading ..." );
           the try { 
            TimeUnit.SECONDS.sleep ( 3 );
             // wait 
            CyclicBarrier.await (); 
          } the catch (InterruptedException | a BrokenBarrierException E) { 
            e.printStackTrace (); 
          } 
        }) Start ();. 
      } 
      // sleep for 10 seconds, and then into the next round 
      TimeUnit.SECONDS.sleep (10 ); 
    } 
  } 
} 

/ *   execution result ( for reference only): 
    the Thread-0 IS .. Reading 
    the Thread-IS. 1 .. Reading 
    the Thread-2 IS .. Reading 
    the Thread Start-Writing. 1 .. 
    --------- 
    the Thread-IS. 3 .. Reading 
    the Thread Reading .. IS -4 
    the Thread-IS. 5 .. Reading 
    the Thread Start. 5-Writing .. 
    --------- 
* /

PS: Here simulate multiple threads to perform read operations, all read after write operation is performed; after read, write ...... can be understood as a simple reconciliation system.

 

Code here for reference only to facilitate understanding the use of the class. In fact every thread creation is unreasonable (can use the thread pool, because no analysis, not used here).

 

summary

 

CyclicBarrier can also be understood as the inverse of the counter, which is somewhat similar to the CountDownLatch. The latter is a "one-off", while the former is "recyclable," the

 

 

Stay hungry, stay foolish.

PS: This article first appeared in the public micro-channel number] [WriteOnRead.

Guess you like

Origin www.cnblogs.com/jaxer/p/11323722.html