一CyclicBarrier
控制所有线程等待,知道达到某种条件,所有的线程才会继续走下去
- 是一个同步工具类
- 它允许一组线程互相等待,直到到达某个公共屏障点才停止等待
- 与CountDownLatch不同的是该barrier(屏障)在释放等待线程后可以重用,所以称它为循环(Cyclic)的屏障(Barrier)。
- CyclicBarrier支持一个可选的Runnable命令,在一组线程中的最后一个线程到达之后(但在释放所有线程之前),该命令只在每个屏障点运行一次。若在继续所有参与线程之前更新共享状态,此屏障操作很有用。
- 对于失败的同步尝试,CyclicBarrier 使用了一种要么全部要么全不 (all-or-none) 的破坏模式:如果因为中断、失败或者超时等原因,导致线程过早地离开了屏障点,那么在该屏障点等待的其他所有线程也将通过 BrokenBarrierException(如果它们几乎同时被中断,则用 InterruptedException)以反常的方式离开。
二方法
- CyclicBarrier(int parties, Runnable barrierAction):
- parties:屏障拦截的线程数量,当屏障撤销时,先执行barrierAction,然后在释放所有线程。
- CyclicBarrier(int parties): barrierAction默认为null
- int await() :
- 当前线程等待直到所有线程都调用了该屏障的await()方法
- 如果当前线程不是将到达的最后一个线程,将会被阻塞。解除阻塞的情况有以下几种
- 最后一个线程调用await()
- 当前线程被中断
- 其他正在该CyclicBarrier上等待的线程被中断
- 其他正在该CyclicBarrier上等待的线程超时
- 其他某个线程调用该CyclicBarrier的reset()方法
- 如果当前线程在进入此方法时已经设置了该线程的中断状态或者在等待时被中断,将抛出InterruptedException,并且清除当前线程的已中断状态。
- 如果在线程处于等待状态时barrier被reset()或者在调用await()时 barrier 被损坏,将抛出 BrokenBarrierException 异常。
- 如果任何线程在等待时被中断,则其他所有等待线程都将抛出 BrokenBarrierException 异常,并将 barrier 置于损坏状态。
- 如果当前线程是最后一个将要到达的线程,并且构造方法中提供了一个非空的屏障操作(barrierAction),那么在允许其他线程继续运行之前,当前线程将运行该操作。
- 如果在执行屏障操作过程中发生异常,则该异常将传播到当前线程中,并将 barrier 置于损坏状态。
- 返回值为当前线程的索引,0表示当前线程是最后一个到达的线程
- int await(long timeout, TimeUnit unit) :
- 在await()的基础上增加超时机制,如果超出指定的等待时间,则抛出 TimeoutException 异常。如果该时间小于等于零,则此方法根本不会等待
- void reset():将屏障重置为其初始状态。如果所有参与者目前都在屏障处等待,则它们将返回,同时抛出一个BrokenBarrierException。
int getnumberwaiting():返回当前在屏障处等待的参与者数目
3案例
public class CyclicBarrierTest {
public static void main(String[] args) {
ExecutorService service = Executors.newCachedThreadPool();
//屏障点3,表示需要3个线程都到屏障点才可以继续走下去,
final CyclicBarrier cb = new CyclicBarrier(3);
for(int i=0;i<3;i++){//测试的时候可以设置比3大的数
Runnable runnable = new Runnable(){
public void run(){
try {
Thread.sleep((long)(Math.random()*5000));
System.out.println(Thread.currentThread().getName() +"到地点1,当前已有" + (cb.getNumberWaiting()+1) + "个在等待。");
cb.await();
System.out.println("地点1已经有3个人到达了,可以先去下个地点了");
Thread.sleep((long)(Math.random()*5000));
System.out.println(Thread.currentThread().getName() +"到地点2,当前已有" + (cb.getNumberWaiting()+1) + "个在等待。");
cb.await();
System.out.println("地点2已经有3个人到达了,可以先去下个地点了");
Thread.sleep((long)(Math.random()*5000));
System.out.println(Thread.currentThread().getName() +"到地点3,当前已有" + (cb.getNumberWaiting()+1) + "个在等待。");
cb.await();
System.out.println("地点3已经有3个人到达了,可以先去下个地点了");
} catch (Exception e) {
e.printStackTrace();
}
}
};
service.execute(runnable);
}
service.shutdown();
}
}
4结果分析
pool-1-thread-3到地点1,当前已有1个在等待。
pool-1-thread-1到地点1,当前已有2个在等待。
pool-1-thread-2到地点1,当前已有3个在等待。----解释
多个线程都堵在地点1,知道线程数满足大于等于屏障数才继续走下去,否则会一直等待
----解释
地点1已经有3个人到达了,可以先去下个地点了
地点1已经有3个人到达了,可以先去下个地点了
地点1已经有3个人到达了,可以先去下个地点了
pool-1-thread-1到地点2,当前已有1个在等待。
pool-1-thread-2到地点2,当前已有2个在等待。
pool-1-thread-3到地点2,当前已有3个在等待。
地点2已经有3个人到达了,可以先去下个地点了
地点2已经有3个人到达了,可以先去下个地点了
地点2已经有3个人到达了,可以先去下个地点了
pool-1-thread-1到地点3,当前已有1个在等待。
pool-1-thread-2到地点3,当前已有2个在等待。
pool-1-thread-3到地点3,当前已有3个在等待。
地点3已经有3个人到达了,可以先去下个地点了
地点3已经有3个人到达了,可以先去下个地点了
地点3已经有3个人到达了,可以先去下个地点了
这边文章写得非常好