源码解析-CyclicBarrier

CyclicBarrier JUC包下 相当于可重复使用的CountDownLauth

之前聊过 CountDownLauth类似一种栅栏,条件每满足一次 state-1 ,state减到0时 打开栅栏释放所有阻塞住的线程

CountDownLautch相当于一次性的栅栏,释放过一次后便无用了。而CyclicBarrier 相当于可重复使用的栅栏。

CountDownLautch是基于AQS实现的,而CyclicBarrier是基于Condition实现的

基本使用

 new CyclicBarrier( int parties, Runnable barrierAction)  

第一个参数是栅栏的条件次数,第二个是栅栏准备释放之前执行的操作(由最后一个线程执行)。

源码分析

CyclicBarrier几个属性

Genetation : 静态内部类  代表栅栏一代版本  内部属性broken代表当前版本是否终结

ReentrantLock : 内部一个锁

Condition : 用来唤醒线程

parties : 初始化的栅栏条件数

Runnable : 栅栏打开之前要执行的操作

count : 当前计数,每await()一次-1

1. CyclicBarrier() 构造方法 没啥好说的

2.await()  每一个线程调用await()时

 dowait() 

 

 

 先上锁

try{

  获取当前CyclicBarrier版本;

  如果版本已经终结,抛异常;

  if (线程中断) {
    终结当前版本,重置count,唤醒所有线程;

    抛中断异常

  }

  count计数--;

  if (如果计数为0 也就是达到了释放栅栏条件 ){

    执行Runnable中的操作;

    开启下一个CyclicBarrier版本;

    if (如果中途执行Runnable操作失败了报错了){

      最后也一定会 终结当前版本,重置count,唤醒所有线程;

    }

  }

}

下边是for循环死循环 

for ( ; ; ){

  try{

    执行condition.await()方法;

  catch(中断异常){

    如果中途被中断,重置版本,重置count,唤醒所有线程;

  }

  if (版本终结){

    抛异常

  }

  if (获取的版本 已经不是当前版本){

    返回当前计数

  }

  if(等待超时) {
    重置,并抛超时异常;
  }

finally{ 解锁}

}

3.  nextGeneration()  当栅栏达到条件执行此方法   将condition.await()的线程全部唤醒,重置count,换一个新版本

4.  reset()  更简单了  终结现在的版本,全部重置并开始一个新版本

什么时候栅栏会被打破,总结如下:

  1. 中断,我们说了,如果某个等待的线程发生了中断,那么会打破栅栏,同时抛出 InterruptedException 异常;
  2. 超时,打破栅栏,同时抛出 TimeoutException 异常;
  3. 指定执行的操作抛出了异常,这个我们前面也说过。
原文地址:https://www.cnblogs.com/ttaall/p/13941535.html