2.CyclicBarrier
CyclicBarrier 的字面意思是可循环使用(Cyclic)的屏障(Barrier)。它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活。CyclicBarrier默认的构造方法是CyclicBarrier(int parties),其参数表示屏障拦截的线程数量,每个线程调用await方法告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞。
当一个线程到达集合点时,它将调用await()方法等待其它的线程。线程调用await()方法后,CyclicBarrier将阻塞这个线程,并将它置入休眠状态等待其它线程的到来。等最后一个线程调用await()方法时,CyclicBarrier将唤醒所有等待的线程,然后这些线程将继续执行。CyclicBarrier可以传入另一个Runnable对象作为初始化参数。当所有的线程都到达集合点后,CyclicBarrier类将Runnable对象作为线程执行。
方法 await():使线程置入休眠直到最后一个线程的到来之后唤醒所有休眠的线程 CyclicBarrier类有两个常用的构造方法: ( 1 )CyclicBarrier( int parties) 这里的parties也是一个计数器,例如,初始化时parties里的计数是 3 ,于是拥有该CyclicBarrier对象的线程当parties的计数为 3 时就唤醒,注意:这里parties里的计数在运行时当调用CyclicBarrier:await()时,计数就加 1 ,一直加到初始的值。 ( 2 )CyclicBarrier( int parties, Runnable barrierAction) 这里的parties与上一个构造方法的解释是一样的,这里需要解释的是第二个入参(Runnable barrierAction),这个参数是一个实现Runnable接口的类的对象,也就是说当parties加到初始值时就触发barrierAction的内容。 |
案例场景:有4个游戏玩家玩游戏,游戏有三个关卡,每个关卡必须要所有玩家都到达后才能允许通过。其实这个场景里的玩家中如果有玩家A先到了关卡1,他必须等到其他所有玩家都到达关卡1时才能通过,也就是说线程之间需要相互等待。这和CountDownLatch的应用场景有区别,CountDownLatch里的线程是到了运行的目标后继续干自己的其他事情,而这里的线程需要等待其他线程后才能继续完成后面的工作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | package com.itszt.test3; import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; /** * 测试CyclicBarrier */ public class CyclicBarrierTest { public static void main(String[] args) { CyclicBarrier cyclicBarrier = new CyclicBarrier( 4 , new Runnable() { @Override public void run() { System.out.println( "所有玩家进入第 2 关!" ); } }); for ( int i = 1 ; i <= 4 ; i++) { new Thread( new Player(i, cyclicBarrier)).start(); } } } /** * 玩家类 * * @author itmyhome */ class Player implements Runnable { private CyclicBarrier cyclicBarrier; private int id; public Player( int id, CyclicBarrier cyclicBarrier) { this .cyclicBarrier = cyclicBarrier; this .id = id; } @Override public void run() { try { System.out.println( "玩家" + id + "正在玩第 1 关..." ); cyclicBarrier.await(); System.out.println( "玩家" + id + "进入第 2 关..." ); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } } } |
代码执行结果如下:
玩家 1 正在玩第 1 关... 玩家 3 正在玩第 1 关... 玩家 2 正在玩第 1 关... 玩家 4 正在玩第 1 关... 所有玩家进入第 2 关! 玩家 4 进入第 2 关... 玩家 1 进入第 2 关... 玩家 3 进入第 2 关... 玩家 2 进入第 2 关... |