From CyclicBarrier to AQS

Write in front

CyclicBarrier source code learning AQS

demo

That is to let multiple threads execute together, and multiple threads reach the fence point at the same time. When the thread that reaches the fence point is equal to count, all threads execute down

public static void main(String[] args) throws Exception {
    
    
   CyclicBarrier cyclicBarrier = new CyclicBarrier(11, new Runnable() {
    
    
       public void run() {
    
    
           System.out.println("所有任务执行完成执行的逻辑");
       }
   });
   AtomicInteger num = new AtomicInteger(10);
   for (int i = 0; i < 10; i++) {
    
    
       new Thread(()->{
    
    
           num.decrementAndGet();
           System.out.println("index: " + num);
           try {
    
    
               cyclicBarrier.await();
           } catch (InterruptedException e) {
    
    
               e.printStackTrace();
           } catch (BrokenBarrierException e) {
    
    
               e.printStackTrace();
           }

       }).start();
   }
   cyclicBarrier.await();
   System.out.println("全部到达屏障....");
}
index: 9
index: 7
index: 8
index: 6
index: 5
index: 4
index: 3
index: 2
index: 1
index: 0
所有任务执行完成执行的逻辑
全部到达屏障....

The construction method, the callback function can be called without passing the construction method with a parameter.

public CyclicBarrier(int parties, Runnable barrierAction) {
    
    
    if (parties <= 0) throw new IllegalArgumentException();
    this.parties = parties;
    this.count = parties;
    this.barrierCommand = barrierAction;
}
  • Create a CyclicBarrier object, you can not pass the callback function
  • Mainly the count value, if this value is 0, the thread will no longer block and start execution
  • The role of patties is to record, which can be used next time. Assign this value to count, which is equivalent to reset
  • Call cyclicBarrier.await();

cyclicBarrier.await

Finally, the following method is called, this is a simple method

private int dowait(boolean timed, long nanos)
   throws InterruptedException, BrokenBarrierException,
          TimeoutException {
    
    
   //创建cyclicBarrier对象默认创建ReentrantLock
   final ReentrantLock lock = this.lock;
   //锁住 以下只有一个线程执行 其余线程在clh队列
   lock.lock();
   try {
    
    
       //此对象只有一个属性用于判断栅栏是否损坏
       final Generation g = generation;
       if (g.broken)
           throw new BrokenBarrierException();
       if (Thread.interrupted()) {
    
    
           breakBarrier();
           throw new InterruptedException();
       }
       //将count--操作。就是每次await都减一
       int index = --count;
       //如果等于0,说明都减完了,可以往下执行逻辑了
       if (index == 0) {
    
      // tripped
           boolean ranAction = false;
           try {
    
    
               final Runnable command = barrierCommand;
               //执行回调函数
               if (command != null)
                   command.run();
               ranAction = true;
               //唤醒所有等待线程 重置属性,为下一次栅栏使用
               nextGeneration();
               return 0;
           } finally {
    
    
               if (!ranAction)
                   breakBarrier();
           }
       }
       for (;;) {
    
    
           try {
    
    
               //如果没有等待时间
               if (!timed)
                   //等待被唤醒
                   trip.await();
                   //等待被唤醒有时间限制
               else if (nanos > 0L)
                   nanos = trip.awaitNanos(nanos);
           } catch (InterruptedException ie) {
    
    
               if (g == generation && ! g.broken) {
    
    
                   breakBarrier();
                   throw ie;
               } else {
    
    
                   Thread.currentThread().interrupt();
               }
           }
           //是否损坏
           if (g.broken)
               throw new BrokenBarrierException();
           //如果generation已经重置 说明已经全都都走完 此时直接返回
           if (g != generation)
               return index;
           if (timed && nanos <= 0L) {
    
    
               breakBarrier();
               throw new TimeoutException();
           }
       }
   } finally {
    
    
       lock.unlock();
   }
}
  • The logic description has been commented in the code
  • Get the lock first, only one thread can come in at this time
  • According to the demo as an example, the count at this time is 11, and each thread needs to execute-(subtraction) operation
  • If count == 0 after subtraction, it means that the specified number of threads has been reached, and I can execute the following business logic code
  • If count == 0, execute the callback function, then wake up the remaining 10 waiting threads and return 0
  • If count != 0, it means that the current thread is not the last one, the threads have not yet arrived, and the current thread also needs to be blocked
  • Use ReentrantLock and condition to wait and wake up, please refer to the previous content for the specific implementation of the bottom layer

This type of source code is relatively simple, which is a disguised application using ReentrantLock and condition

The above is the general source code analysis of CyclicBarrier. If there are any mistakes, criticisms and corrections are welcome.

Guess you like

Origin blog.csdn.net/qq_37904966/article/details/113481996
AQS
AQS