Java Concurrency series (8) CyclicBarrier source code analysis

In real life we ​​often encounter such a scenario, before carrying out an activity need to wait for people all together and we have to start. For example, to wait for a meal the whole family seat of honor was Dongkuaizi, when traveling to wait for all the people in attendance before departure, the athletes have to wait for the game to play after the start.

In JUC package provides us with a synchronization tools can simulate such scenarios, it is CyclicBarrier class. CyclicBarrier may be implemented using a class group of threads waiting for each other, subsequent operation when all threads reach a point after the barrier.

Inside there is a counter CyclicBarrier class, when each thread reaches the barrier point will be invoked await their obstruction, this time counter is decremented by one, when the counter is reduced to 0 when all factors are invoked await blocked thread You will wake up. This principle is to achieve a set of threads waiting for each other, let's take a look at what CyclicBarrier member variables.

// synchronize operation of the lock 
Private  Final of ReentrantLock = Lock new new of ReentrantLock ();
 // thread interceptor 
Private  Final for condition Condition TRIP = lock.newCondition ();
 // every time the number of blocked threads 
Private  Final  int parties;
 // performed before updating tasks 
Private  Final Runnable barrierCommand;
 // represents the current generation of fence 
Private Generation Generation = new new Generation ();
 // counter 
Private  int COUNT; 

// static inner classes Generation 
Private  static  class Generation {
   boolean broken = false;
}

Posted CyclicBarrier above all the member variables, you can see inside CyclicBarrier is blocked by conditions to queue trip to the thread, and the internal maintenance of the two parties and variables of type int count, parties to intercept represents the number of each thread , when the value assignment configuration.

internal counter count is the same as its initial value and the parties, with the subsequent call await method each being decremented by 1 until reduced to 0 will all wake up threads.

CyclicBarrier has a static inner classes Generation, object of this class represents the current generation of the fence, on behalf of the Council when the game is like playing a game, which allows you to achieve the cycle wait.

barrierCommand represent tasks performed before updating, when the count reduced to 0 indicate the end of this Council game, we need to go to the next game. All blocked thread will wake up before going to the next game, before you wake up all the threads can perform their tasks by specifying barrierCommand. Next we look at its constructor.

//构造器1
public CyclicBarrier(int parties, Runnable barrierAction) {
   if (parties <= 0) throw new IllegalArgumentException();
   this.parties = parties;
   this.count = parties;
   this.barrierCommand = barrierAction;
}

//构造器2
public CyclicBarrier(int parties) {
   this(parties, null);
}
 

CyclicBarrier has two constructors, construction of which 1 is its core constructor, where you can specify the number of participants in the Council of the game (the number of threads to be blocked) and the Council at the end of the task to be performed, you can see the counter the initial value of the count is set to parties. CyclicBarrier class main function is that the thread arrives at a barrier point to block and wait behind the thread, where it provides two methods waiting are waiting untimed and timed wait.

//非定时等待
public int await() throws InterruptedException, BrokenBarrierException {
   try {
       return dowait(false, 0L);
   } catch (TimeoutException toe) {
       throw new Error(toe);
   }
}

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

You can see whether it is regular or non-regular wait wait, they all call dowait method, but it is a different argument passed. Here we take a look at dowait methods are done.

// core Wait method 
Private  int dowait ( Boolean Timed, Long of nanos) 
 throws InterruptedException, a BrokenBarrierException, a TimeoutException {
    Final of ReentrantLock = Lock the this .lock; 
   Lock.lock (); 
   the try {
        Final Generation G = Generation;
        // check whether the current fence tipped 
       IF (g.broken) {
            the throw  new new BrokenBarrierException (); 
       } 
       // check if the current thread is interrupted 
       IF (Thread.interrupted ()) {
            // if the current thread is interrupted would do the following three things
           // 1. knocked current fence
            @ 2 wakeup intercept all threads
            // 3. interrupt exception thrown 
           breakBarrier ();
            the throw  new new InterruptedException (); 
       } 
      // every time the counter is decremented by the value. 1 
      int index = - COUNT;
       // value of the down counter is 0, and all the threads need to wake up next converted to 
      IF (index == 0 ) {
           Boolean ranAction = to false ;
           the try {
               // wake runs the specified tasks until all threads 
              Final the Runnable = Command barrierCommand;
               IF ! (Command = null ) {
                  command.run (); 
              } 
              ranAction = to true ;
               // wake up all the threads and go to the next 
              NextGeneration ();
               return 0 ; 
          } a finally {
               // make sure that all threads can not wake up when the task is successfully executed 
              IF (! ranAction) { 
                  breakBarrier (); 
              } 
          } 
      } 

      // If the cycle counter is not 0 is executed 
      for (;;) {
           the try {
               // the passed parameters to determine the timing is a timing wait or a non-wait 
              IF (! timed) {
                  trip.await (); 
              } the else  if (of nanos> 0L ) { 
                  of nanos = trip.awaitNanos (of nanos); 
              } 
          } the catch (InterruptedException IE) {
               // if the current thread is interrupted during the waiting tipped fence wake other threads 
              if (G Generation == &&! g.broken) { 
                  breakBarrier (); 
                  the throw IE; 
              } the else {
                   // if the abnormality has been completed before the capture interrupt waiting on the fence, 
                   // directly call the interrupt operation 
                  Thread.currentThread () .interrupt (); 
              } 
          }
          // If the thread operation because the fence is knocked awakened exception is thrown 
          IF (g.broken) {
               the throw  new new a BrokenBarrierException (); 
          } 
          // If the thread is awakened because the replacement operation returns the value of the counter 
          IF (G =! Generation) {
               return index; 
          } 
          // if the thread because of the time to be woken up and then thrown tipped fences and 
          IF (Timed of nanos && <= 0L ) { 
              breakBarrier (); 
              the throw  new new a TimeoutException (); 
          } 
      } 
   } the finally { 
       lock.unlock (); 
   } 
}

The code posted above comments are more detailed, we just pick some important terms. Can be seen in dowait method every time the count is decremented by one, cut immediately after the judge to see if equal to 0, the task before the specified good if equal to 0, then it will go to perform, then call the method after executing nextGeneration go to the next fence, all threads in the process will wake up, the value of the counter is reset to parties, and finally re-fencing generations, after performing nextGeneration method means that the game into the next game.

If the counter is not equal to 0 at this time, then enters a for loop, a call to determine trip.awaitNanos (nanos) or trip.await () method, both the timing and method of non-corresponding parameters according to the timing wait. If the wait is interrupted during the current thread will execute breakBarrier method is called to break the fence, cut off in the middle it means that the game is set to true generation of broken state and wake up all the threads. At the same time it also shows that there is a thread was interrupted Disc game is over in the waiting process, all previously blocked thread will be woken up.

After waking up the thread will execute the following three judge to see if the method because the call breakBarrier be awakened, if an exception is thrown; if it is normal to see replacement operation to be awakened, if the counter is the value returned; see to see whether the timeout is due to wake up, and if so invokes breakBarrier break the fence and throw an exception. There is also to be noted that, if there was a thread because the wait timeout and quit, then the whole disc game will end, and the other thread will be awakened. The following methods and specific code posted nextGeneration breakBarrier methods.

// switch to the next barrier 
Private  void NextGeneration () {
    // wake condition queue all threads 
   trip.signalAll ();
    // Set the counter value of the number of threads need to intercept the 
   COUNT = parties;
    // reset the fence passages 
   generation = new new Generation (); 
} 

// tipped current fence 
Private  void breakBarrier () {
    // current status to the fence tipped 
   generation.broken = to true ;
    // set the counter value of the number of threads need to intercept the 
   COUNT = parties ;
    // wake up all threads 
   trip.signalAll (); 
}

Above we have the source code by the basic principles of CyclicBarrier speak clearly, Here we have an example of a race to a deep understanding of its use.

class Horse implements Runnable {
   
   private static int counter = 0;
   private final int id = counter++;
   private int strides = 0;
   private static Random rand = new Random(47);
   private static CyclicBarrier barrier;
   
   public Horse(CyclicBarrier b) { barrier = b; }
   
   @Override
   public void run() {
       try {
           while(!Thread.interrupted()) {
               synchronized(this) {
                   //赛马每次随机跑几步
                   strides += rand.nextInt(3);
               }
               barrier.await();
           }
       } catch(Exception e) {
           e.printStackTrace();
       }
   }
   
   public String tracks() {
       StringBuilder s = new StringBuilder();
       for(int i = 0; i < getStrides(); i++) {
           s.append("*");
       }
       s.append(id);
       return s.toString();
   }
   
   public synchronized int getStrides() { return strides; }
   public String toString() { return "Horse " + id + " "; }
   
}
public class HorseRace implements Runnable {
   
   private static final int FINISH_LINE = 75;
   private static List<Horse> horses = new ArrayList<Horse>();
   private static ExecutorService exec = Executors.newCachedThreadPool();
   
   @Override
   public void run() {
       StringBuilder s = new StringBuilder();
       //打印赛道边界
       for(int i = 0; i < FINISH_LINE; i++) {
           s.append("=" ); 
       } 
       System.out.println (S); 
       // print racing track 
       for (Horse Horse: Horses) { 
           System.out.println (horse.tracks ()); 
       } 
       // determines whether or not the end 
       for (Horse Horse: Horses) {
            IF (horse.getStrides ()> = FINISH_LINE) { 
               System.out.println (Horse + "Won!" ); 
               exec.shutdownNow (); 
               return ; 
           } 
       } 
       // rest in the next specified time and then round 
       the try { 
           TimeUnit.MILLISECONDS.sleep ( 200 is ); 
       } the catch(InterruptedException e) {
           System.out.println("barrier-action sleep interrupted");
       }
   }
   
   public static void main(String[] args) {
       CyclicBarrier barrier = new CyclicBarrier(7, new HorseRace());
       for(int i = 0; i < 7; i++) {
           Horse horse = new Horse(barrier);
           horses.add(horse);
           exec.execute(horse);
       }
   }
   
}

The racing program mainly through non-stop printing each horse racing track in the current console, in order to achieve the effect of dynamic display. The whole game has multiple rounds, each round will be random times each race took a few steps and then invoked await wait, when all racing to finish the round will perform the task of the current track to control all racehorse print table.

So that each one down the track the race horses are in constant growth, when a horse racing track where the first increase to the value specified time will end the whole game, the race to become the winner of the whole game! Operating results of the program are as follows:

At this point we will inevitably be some CyclicBarrier compared with CountDownLatch. Both classes implement a set of threads to wait before it reaches a certain condition, they have an internal counter when the counter is continuously reduced to zero all blocked thread will be awakened. 

There is a difference of CyclicBarrier counter controlled by themselves, and CountDownLatch counter by the user to control the thread invoked await CyclicBarrier not only put their blocking will also counter by 1, and in CountDownLatch threads invoked await just will block themselves will not reduce the value of the counter.

In addition, CountDownLatch only one interception, interception and CyclicBarrier cycle can be achieved. It may be implemented with general CyclicBarrier CountDownLatch function, but not vice versa, such as the above horse program can be implemented using CyclicBarrier. Together, these two classes of similarities and differences generally the case, as to when to use CyclicBarrier, when to use CountDownLatch, also need the reader to draw the line.

AQS

 

Guess you like

Origin www.cnblogs.com/iwyc/p/11266032.html