基于jdk1.8源码进行分析的。
继承结构
public class CyclicBarrier
构造方法
CyclicBarrier(int parties)
public CyclicBarrier(int parties) {
this(parties, null);
}
通过源码我们看到是通过调用另外一个构造方法实现的。
CyclicBarrier(int parties, Runnable barrierAction)
public CyclicBarrier(int parties, Runnable barrierAction) {
if (parties <= 0) throw new IllegalArgumentException();
this.parties = parties;
this.count = parties;
this.barrierCommand = barrierAction;
}
内部类
Generation
private static class Generation {
//用来表示当前的屏障是否被打破了
boolean broken = false;
}
每个CyclicBarrier实例中也有一个Generation域。
成员属性
/** The lock for guarding barrier entry */
//所有方法都通过这个锁来同步
//之所以不使用内置锁主要是因为需要抛出异常
//此外这里需要的实际上是共享锁,而内置锁不能实现共享锁
private final ReentrantLock lock = new ReentrantLock();
/** Condition to wait on until tripped */
//通过lock得到的一个状态变量
private final Condition trip = lock.newCondition();
/** The number of parties */
//通过构造器传入的参数,表示总的等待线程的数量
private final int parties;
/* The command to run when tripped */
当屏障正常打开后运行的程序,通过最后一个调用await的线程来执行
private final Runnable barrierCommand;
/** The current generation */
//当前的Generation。
//每当屏障失效或者开闸之后都会自动替换掉。从而实现重置的功能。
private Generation generation = new Generation();
核心方法
await()
调用await()的线程会等待直到有足够数量的线程调用await——也就是开闸状态。
当最后一个线程到达,或者
- 有其他线程中断当前线程。则抛出interruptException
- 指定了限时操作,并到达线程,则抛出TimeoutException
- 如果barrier被重置,或者屏障处于打破状态,则抛出BrokenBarrierException
public int await() throws InterruptedException, BrokenBarrierException {
try {
return dowait(false, 0L);
} catch (TimeoutException toe) {
throw new Error(toe); // cannot happen
}
}
通过源码我们看到是通过dowait实现的。再看主方法源码实现之前,我们先看一下以下两个方法,有助于后面的理解。
nextGeneration()
private void nextGeneration() {
// signal completion of last generation
//唤醒所有等待的线程
trip.signalAll();
// set up next generation
//更新当前线程数量,构造方法传入的,相当于重置剩余线程数量
count = parties;
//创建新的Generation,相当于状态重置
generation = new Generation();
}
breakBarrier()
private void breakBarrier() {
//改变当前generation的状态,相当于屏障打破状态
generation.broken = true;
//记录更新线程数量,相当于重置数量
count = parties;
//唤醒所有线程
trip.signalAll();
}
上面两个方法比较简单,此处不再一一额外解释。下面我们看主方法源码。
dowait(boolean timed, long nanos)
private int dowait(boolean timed, long nanos)
throws InterruptedException, BrokenBarrierException,
TimeoutException {
//记录当前lock锁
final ReentrantLock lock = this.lock;
//上锁
lock.lock();
try {
//记录当前的屏障的状态
//后者是成员属性,private Generation generation = new Generation();
final Generation g = generation;
//如果成立,说明屏障被打破,抛出异常
if (g.broken)
throw new BrokenBarrierException();
//线程中断,抛出异常
if (Thread.interrupted()) {
//如果当前线程被中断,则使得当前generation处于打破状态,重置剩余count。
//并且唤醒状态变量。这时候其他线程会传播BrokenBarrierException.
breakBarrier();//这里前面已经粘贴
//抛出异常
throw new InterruptedException();
}
//进入这里,说明状态没有被打破,且没有发生中断等异常情况
//线程数量-1操作
int index = --count;
//这里也就是要开闸操作
if (index == 0) { //如果开闸了,正常运行直接返回0就退出了
//状态值
boolean ranAction = false;
try {
//当开闸了,记录运行变量
final Runnable command = barrierCommand;
//有相应的线程
if (command != null)
command.run();//当前线程调用command的run方法
ranAction = true;//修改状态值
//唤醒所有线程
nextGeneration();//创建新的Generation,相当于重置状态
//返回0
return 0;
} finally {
//没有启动成功
if (!ranAction)
//打破状态
breakBarrier();
}
}
// loop until tripped, broken, interrupted, or timed out
//死循环
//执行到这里,说明屏障没有被打破,线程没有被中断,且没有意外,最后一个线程还没有到达
for (;;) {
try {
//如果没有设置等待时间,则一直等待,直到其它线程唤醒
if (!timed)
//进入等待
trip.await();
//如果设置了等待时间,则等待指定的时间。调用对应的condition方法
else if (nanos > 0L)
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.
//翻译内容如下:
/*即使我们没有被打断,我们即将完成等待,
*因此这个中断被认为“属于”后续执行
*/
//这种捕获了InterruptException之后调用
//Thread.currentThread().interrupt()是一种通用的方式。
//其实就是为了保存中断状态,从而让其他更高层次的代码注意到这个中断。
//但是需要注意的是这里需要其他代码予以配合才行
//否则这样做其实是比较危险的一种方式。
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();
}
}
源码中注释内容我觉得还是比较清晰的,下面我们继续看reset方法的实现。
reset()
public void reset() {
//记录当前锁
final ReentrantLock lock = this.lock;
//上锁
lock.lock();
try {
//打破屏障,重置数量
breakBarrier(); // break the current generation
//创建新的generation,重置数量
nextGeneration(); // start a new generation
} finally {
//释放锁
lock.unlock();
}
}
通过源码分析来看reset方法实现起来,确实比较简单。以上就是整个核心方法的实现过程的源码分析。
package demo;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeoutException;
/**
* CyclicBarrier测试例程
* @ClassName: CyclicBarrierDemo
* @Description: TODO
* @author BurgessLee
* @date 2019年4月30日
*
*/
public class CyclicBarrierDemo {
public static Integer NUM = 3;
public static void main(String[] args) {
// CyclicBarrier cyclicBarrier = new CyclicBarrier(NUM);
//如果出现异常情况,那么只会影响当前的创建时的command,不会影响其他线程
// CyclicBarrier cyclicBarrier = new CyclicBarrier(1, new Runnable() {
//
// @Override
// public void run() {
// try {
// System.out.println(Thread.currentThread().getName() +"-start..");
// int i = 1/0;
// System.out.println(Thread.currentThread().getName() +"-end...");
// } catch (Exception e) {
// e.printStackTrace();
// }
// System.out.println("============================");
// }
// });
// new Thread(new Runnable() {
//
// @Override
// public void run() {
// try {
// System.out.println(Thread.currentThread().getName() +"-start...----");
// cyclicBarrier.await();
// System.out.println(Thread.currentThread().getName() +"-end...----");
// } catch (Exception e) {
// e.printStackTrace();
// }
// }
// },"Thread0").start();
//在打破屏障之前,就算是await时间过程,那么最后处理的command也不会抛出异常
// CyclicBarrier cyclicBarrier = new CyclicBarrier(1, new Runnable() {
//
// @Override
// public void run() {
// try {
// System.out.println(Thread.currentThread().getName() +"-start..");
// TimeUnit.MICROSECONDS.sleep(20);
// System.out.println(Thread.currentThread().getName() +"-end...");
// } catch (Exception e) {
// e.printStackTrace();
// }
// System.out.println("我会正常等待,不会抛出异常");
// }
// });
// new Thread(new Runnable() {
//
// @Override
// public void run() {
// try {
// System.out.println(Thread.currentThread().getName() +"-start...----");
// cyclicBarrier.await(10,TimeUnit.SECONDS);
// System.out.println(Thread.currentThread().getName() +"-end...----");
// } catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// } catch (BrokenBarrierException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// } catch (TimeoutException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
// }
// },"Thread0").start();
//当所有线程都到达barrier之后,然后调用CyclicBarrier自带的Runnable里面的run方法
// CyclicBarrier cyclicBarrier = new CyclicBarrier(NUM,new Runnable() {
//
// @Override
// public void run() {
// try {
// System.out.println(Thread.currentThread().getName() +"-start...----");
// Thread.sleep(2000);
// System.out.println(Thread.currentThread().getName() +"-end...----");
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// System.out.println("我最后执行,我是来收尾工作的");
// }
// });
// new Thread(new Runnable() {
//
// @Override
// public void run() {
// try {
// System.out.println(Thread.currentThread().getName() +"-start...");
// cyclicBarrier.await();
// System.out.println(Thread.currentThread().getName() +"-end...");
// } catch (Exception e) {
// e.printStackTrace();
// }
// }
// },"Thread0").start();
// new Thread(new Runnable() {
//
// @Override
// public void run() {
// try {
// System.out.println(Thread.currentThread().getName() +"-start...");
// cyclicBarrier.await();
// System.out.println(Thread.currentThread().getName() +"-end...");
// } catch (Exception e) {
// e.printStackTrace();
// }
// }
// },"Thread1").start();
//
// new Thread(new Runnable() {
//
// @Override
// public void run() {
// try {
// System.out.println(Thread.currentThread().getName() +"-start...");
// cyclicBarrier.await();
// System.out.println(Thread.currentThread().getName() +"-end...");
// } catch (Exception e) {
// e.printStackTrace();
// }
// }
// },"Thread2").start();
//没有打破屏障,那么等待时间到了,会抛出异常
// CyclicBarrier cyclicBarrier = new CyclicBarrier(NUM);
// new Thread(new Runnable() {
//
// @Override
// public void run() {
// try {
// System.out.println(Thread.currentThread().getName() +"-start...");
// cyclicBarrier.await(2, TimeUnit.SECONDS);
// System.out.println(Thread.currentThread().getName() +"-end...");
// } catch (Exception e) {
// e.printStackTrace();
// }
// }
// },"Thread0").start();
// new Thread(new Runnable() {
//
// @Override
// public void run() {
// try {
// System.out.println(Thread.currentThread().getName() +"-start...");
// cyclicBarrier.await();
// Thread.sleep(100);
// System.out.println(Thread.currentThread().getName() +"-end...");
// } catch (Exception e) {
// e.printStackTrace();
// }
// }
// },"Thread1").start();
//NUM=2等待时间到了,都执行接下来的任务
// new Thread(new Runnable() {
//
// @Override
// public void run() {
// try {
// System.out.println(Thread.currentThread().getName() +"-start...");
// cyclicBarrier.await(1, TimeUnit.SECONDS);
// System.out.println(Thread.currentThread().getName() +"-end...");
// } catch (Exception e) {
// e.printStackTrace();
// }
// }
// },"Thread0").start();
// new Thread(new Runnable() {
//
// @Override
// public void run() {
// try {
// System.out.println(Thread.currentThread().getName() +"-start...");
// cyclicBarrier.await();
// Thread.sleep(3000);
// System.out.println(Thread.currentThread().getName() +"-end...");
// } catch (Exception e) {
// e.printStackTrace();
// }
// }
// },"Thread1").start();
//
//下面这个可能更加清楚的展示了CyclicBarrier的更合理有效的解释
// Scanner scanner = new Scanner(System.in);
// while(true) {
// System.out.println("please input a number:");
// String nextLine = scanner.nextLine();
// if("".equals(nextLine) || nextLine == null) {
// continue;
// }else if("0".equals(nextLine)) {
// System.out.println("初始化创建线程1个");
// new Thread(new Runnable() {
//
// @Override
// public void run() {
// try {
// System.out.println(Thread.currentThread().getName() +"-start...");
// cyclicBarrier.await();
// System.out.println(Thread.currentThread().getName() +"-end...");
// } catch (InterruptedException e) {
// e.printStackTrace();
// } catch (BrokenBarrierException e) {
// e.printStackTrace();
// }
// }
// },"Thread0").start();
// }else {
// System.out.println("+1个线程");
// new Thread(new Runnable() {
//
// @Override
// public void run() {
// try {
// System.out.println(Thread.currentThread().getName() +"-start...");
// cyclicBarrier.await();
// System.out.println(Thread.currentThread().getName() +"-end...");
// } catch (InterruptedException e) {
// e.printStackTrace();
// } catch (BrokenBarrierException e) {
// e.printStackTrace();
// }
// }
// },"Thread"+nextLine).start();
// }
// if(Thread.activeCount() == 4) {//还有一个守护线程,你知道的
// System.out.println("结束了,不和你玩了");
// break;
// }
// }
//当有四个线程的时候,会发现有一个线程启动了,但是没有结束,说明在等待信号
// new Thread(new Runnable() {
//
// @Override
// public void run() {
// try {
// System.out.println(Thread.currentThread().getName() +"-start...");
// cyclicBarrier.await();
// System.out.println(Thread.currentThread().getName() +"-end...");
// } catch (InterruptedException e) {
// e.printStackTrace();
// } catch (BrokenBarrierException e) {
// e.printStackTrace();
// }
// }
// },"Thread0").start();
// new Thread(new Runnable() {
//
// @Override
// public void run() {
// try {
// System.out.println(Thread.currentThread().getName() +"-start...");
// cyclicBarrier.await();
// System.out.println(Thread.currentThread().getName() +"-end...");
// } catch (InterruptedException e) {
// e.printStackTrace();
// } catch (BrokenBarrierException e) {
// e.printStackTrace();
// }
// }
// },"Thread1").start();
// new Thread(new Runnable() {
//
// @Override
// public void run() {
// try {
// System.out.println(Thread.currentThread().getName() +"-start...");
// cyclicBarrier.await();
// System.out.println(Thread.currentThread().getName() +"-end...");
// } catch (InterruptedException e) {
// e.printStackTrace();
// } catch (BrokenBarrierException e) {
// e.printStackTrace();
// }
// }
// },"Thread2").start();
// new Thread(new Runnable() {
//
// @Override
// public void run() {
// try {
// System.out.println(Thread.currentThread().getName() +"-start...");
// cyclicBarrier.await();
// System.out.println(Thread.currentThread().getName() +"-end...");
// } catch (InterruptedException e) {
// e.printStackTrace();
// } catch (BrokenBarrierException e) {
// e.printStackTrace();
// }
// }
// },"Thread3").start();
//三个线程执行,当三个线程全开始之后再唤醒执行下面的
// new Thread(new Runnable() {
//
// @Override
// public void run() {
// try {
// System.out.println(Thread.currentThread().getName() +"-start...");
// cyclicBarrier.await();
// System.out.println(Thread.currentThread().getName() +"-end...");
// } catch (InterruptedException e) {
// e.printStackTrace();
// } catch (BrokenBarrierException e) {
// e.printStackTrace();
// }
// }
// },"Thread0").start();
// new Thread(new Runnable() {
//
// @Override
// public void run() {
// try {
// System.out.println(Thread.currentThread().getName() +"-start...");
// cyclicBarrier.await();
// System.out.println(Thread.currentThread().getName() +"-end...");
// } catch (InterruptedException e) {
// e.printStackTrace();
// } catch (BrokenBarrierException e) {
// e.printStackTrace();
// }
// }
// },"Thread1").start();
// new Thread(new Runnable() {
//
// @Override
// public void run() {
// try {
// System.out.println(Thread.currentThread().getName() +"-start...");
// cyclicBarrier.await();
// System.out.println(Thread.currentThread().getName() +"-end...");
// } catch (InterruptedException e) {
// e.printStackTrace();
// } catch (BrokenBarrierException e) {
// e.printStackTrace();
// }
// }
// },"Thread2").start();
}
}
以上是所有测试代码运行情况的分析。 下面还有一个DEMO演示了,如果当等待时间到了,却没有打破屏障,那么此时会抛出异常, 到达打破屏障后继续执行任务。
package demo;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
* CyclicBarrier测试例程
* @ClassName: CyclicBarrierDemo2
* @Description: TODO
* @author BurgessLee
* @date 2019年4月30日
*
*/
public class CyclicBarrierDemo2 {
private final static int NUM = 3;
public static void main(String[] args){
final CyclicBarrier barrier = new CyclicBarrier(NUM);
for(int i=0;i<NUM;i++){
if(i==NUM-1){//i=2
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//先休息再开启线程
new Task(barrier).start();
}
else{
new Task(barrier).start();
}
}
}
static class Task extends Thread{
private CyclicBarrier barrier;
public Task(CyclicBarrier barrier){
this.barrier = barrier;
}
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName() + "----start");
barrier.await(3, TimeUnit.SECONDS);//等待3秒,如果所有线程3秒后还没有到达barrier,则会抛异常然后继续往下面运行
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " end");
}
}
}
通过上面的DEMO演示我们可以总结如下内容:
1.CyclicBarrier是可以重用的,但是CountDownLatch不可以。
2.如果实例化CyclicBarrier的时候,传入了第二个参数,那么在到达屏障状态之后,会调用该方法执行对应的处理,如果有异常,那么也不影响其他线程的处理。
3.如果等待超时,且未打破屏障,那么抛出异常,等待打破线程,执行后续任务。
以上就是此次针对CyclicBarrier的源码分析过程了。如果有不对的地方还请指正。