CyclicBarrier是另外一种多线程并发控制实用工具,和CountDownLatch非常相似,比CountDownLatch更复杂且强大。
- 构造方法
//parties表示屏障拦截的线程数量,当屏障撤销时,先执行barrierAction,然后在释放所有线程 public CyclicBarrier(int parties, Runnable barrierAction) //barrierAction默认为null public CyclicBarrier(int parties)
- 主要方法
/* *当前线程等待直到所有线程都调用了该屏障的await()方法 *如果当前线程不是将到达的最后一个线程,将会被阻塞。解除阻塞的情况有以下几种 * 1)最后一个线程调用await() * 2)当前线程被中断 3)其他正在该CyclicBarrier上等待的线程被中断 4)其他正在该CyclicBarrier上等待的线程超时 5)其他某个线程调用该CyclicBarrier的reset()方法 *如果当前线程在进入此方法时已经设置了该线程的中断状态或者在等待时被中断,将抛出InterruptedException,并且清除当前线程的已中断状态。 *如果在线程处于等待状态时barrier被reset()或者在调用await()时 barrier 被损坏,将抛出 BrokenBarrierException 异常。 *如果任何线程在等待时被中断,则其他所有等待线程都将抛出 BrokenBarrierException 异常,并将 barrier 置于损坏状态。 *如果当前线程是最后一个将要到达的线程,并且构造方法中提供了一个非空的屏障操作(barrierAction),那么在允许其他线程继续运行之前, *当前线程将运行该操作。如果在执行屏障操作过程中发生异常,则该异常将传播到当前线程中,并将 barrier 置于损坏状态。 *返回值为当前线程的索引,0表示当前线程是最后一个到达的线程 */ public int await() throws InterruptedException, BrokenBarrierException //在await()的基础上增加超时机制,如果超出指定的等待时间,则抛出 TimeoutException 异常。如果该时间小于等于零,则此方法根本不会等待。 public int await(long timeout, TimeUnit unit) throws InterruptedException, BrokenBarrierException, TimeoutException //将屏障重置为其初始状态。如果所有参与者目前都在屏障处等待,则它们将返回,同时抛出一个BrokenBarrierException。 public void reset()
例子:
public class CyclicBarrierTest { public static void main(String[] args) throws IOException, InterruptedException { CyclicBarrier barrier = new CyclicBarrier(5,new Runnable() { @Override public void run() { System.out.println(" TEST BEGIN"); } }); ExecutorService executor = Executors.newFixedThreadPool(5); executor.submit(new Thread(new Worker(barrier, "People 1"))); executor.submit(new Thread(new Worker(barrier, "People 2"))); executor.submit(new Thread(new Worker(barrier, "People 3"))); executor.submit(new Thread(new Worker(barrier, "People 4"))); executor.shutdown(); } } class Worker implements Runnable{ // 一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point) private CyclicBarrier barrier; private String name; public Worker(CyclicBarrier barrier,String name){ this.barrier = barrier; this.name = name; } @Override public void run() { try{ System.out.println(name + " TEST START"); // barrier的await方法,在所有参与者都已经在此 barrier 上调用 await 方法之前,将一直等待。 barrier.await(); }catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } } }
CyclicBarrier与CountDownLatch比较
CountDownLatch:一个线程(或者多个),等待另外N个线程完成某个事情之后才能执行;CyclicBarrier:N个线程相互等待,任何一个线程完成之前,所有的线程都必须等待。
CountDownLatch:一次性的;CyclicBarrier:可以重复使用。
CountDownLatch:基于AQS;CyclicBarrier基于锁和Condition。本质上都是依赖于volatile和CAS实现的。