什么是CyclicBarrier?
CyclicBarrier的字面意思是可循环使用(Cyclic)的屏障(Barrier)。它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续工作。
使用场景
当存在需要所有子任务都完成时,才执行主任务,这个时候可以选择使用CyclicBarrier。
代码示例
CyclicBarrierDemo 类
public class CyclicBarrierDemo extends Thread{
public static void main(String[] args) {
// 注意事项:
// 1、设置了第一个参数的值,如果因为某些原因导致没有足够多的线程来调用await
// 这个时候回导致所有的线程都被阻塞
// 2.await(timeout,unit)设置一个超时等待,可以避免1中所提到等待问题
CyclicBarrier cyclicBarrier =new CyclicBarrier(3,new CyclicBarrierDemo());
new DataImportThread("path1",cyclicBarrier).start();
new DataImportThread("path2",cyclicBarrier).start();
new DataImportThread("path3",cyclicBarrier).start();
// 3.cyclicBarrier.reset可以重置计数,可以抛出BrokenBarrierException 从而做出对应处理
// cyclicBarrier.reset();
// TODO 希望三个线程执行结束之后,再做一个汇总处理
}
@Override
public void run() {
System.out.println("开始进行数据汇总和分析");
}
}
DataImportThread 类
public class DataImportThread extends Thread {
private String path;
private CyclicBarrier cyclicBarrier;
public DataImportThread(String path, CyclicBarrier cyclicBarrier) {
this.path = path;
this.cyclicBarrier = cyclicBarrier;
}
@Override
public void run() {
System.out.println("开始导入:"+path+"位置的数据");
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
运行结果:
开始导入:path1位置的数据
开始导入:path3位置的数据
开始导入:path2位置的数据
开始进行数据汇总和分析
Process finished with exit code 0
图解原理
首先这里定义了会有4个线程来处理相关事务,每个线程在执行完自己的代码之后会调用一个await方法,使parties依次递减1,使当前线程阻塞,当四个线程都执行完都调用了await方法之后,就会去调用Runnable中的run方法,执行完成后会唤醒阻塞的线程。此时,会将parties重置为4,可以循环完成线程的阻塞与唤醒,这也就是它的Cyclic实现。