在上一篇文章中我们介绍了同步辅助类CountDownLatch,在Java concurrent包下还有另一个同步辅助类CyclicBarrier与CountDownLatch非常类似,它也允许多个线程在某个点进行同步,但CyclicBarrier类更加强大。
操作方法
- 提供两种构造函数带Runnable的 CyclicBarrier(int parties, Runnable barrierAction)表示线程都同步后执行barrierAction。和不带Runnable。
- await() 方法没被调用一次,计数便会减少1,并阻塞住当前线程。当计数减至0时,阻塞解除,所有在此 CyclicBarrier 上面阻塞的线程开始运行。
与CountDownLatch的不同之处
-
**CountDownLatch对象的作用只能使用一次,当计算减为0之后就不能再使用了。但CyclicBarrier对象可以重复使用。**在计算减为0后,如果再次调用await() 方法,计数就又会变成 N-1,新一轮重新开始,也可以通过reset()重置,这便是 Cyclic 的含义所在。
-
不用向CountDownLatch一样调用countDown()方法
-
CyclicBarrier 的构造函数还可以接受一个 Runnable,会在所有得线程都到达同步点后执行某些操作。
-
CyclicBarrier.await() 方法会抛出一个独有的 BrokenBarrierException。这个异常发生在当某个线程在等待本 CyclicBarrier 时被中断或超时或被重置时,其它同样在这个 CyclicBarrier 上等待的线程便会受到 BrokenBarrierException。意思就是说,同志们,别等了,有个小伙伴已经挂了,咱们如果继续等有可能会一直等下去,所有各回各家吧。
使用实例
该例子在CountDownLatch的例子上进行改进,使用CyclicBarrier类代替结束倒计锁,当CyclicBarrier对象的计算为0时,比赛结束,启动一个线程执行统计:
package MyThread;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
public class Match {
// 模拟了100米赛跑,10名选手已经准备就绪,只等裁判一声令下。当所有人都到达终点时,比赛结束。
public static void main(String[] args) throws InterruptedException {
HashMap<String,String> result=new HashMap<>();
// 开始的倒数锁
final CountDownLatch begin=new CountDownLatch(1) ;
// 结束的倒数锁 使用CyclicBarrier,在所有线程结束后启动统计线程
final CyclicBarrier end=new CyclicBarrier(10, new Statistics(result));
// 十名选手
for (int index = 0; index < 10; index++) {
new Thread(new player(begin,end,result),"player"+index).start();
}
System.out.println("Game Start");
// begin减一,开始游戏
begin.countDown();
// 等待end变为0,即所有选手到达终点
}
}
class player implements Runnable{
// 开始的倒数锁
private final CountDownLatch begin ;
// 结束的倒数锁
private final CyclicBarrier end;
//成绩记录
HashMap<String,String> result;
player(CountDownLatch begin,CyclicBarrier end,HashMap<String,String> result){
this.begin=begin;
this.end=end;
this.result=result;
}
@Override
public void run() {
// TODO Auto-generated method stub
try {
// 如果当前计数为零,则此方法立即返回。
// 等待
begin.await();
Thread.sleep((long) (Math.random() * 10000));
result.put(Thread.currentThread().getName(), new Date().toString());
System.out.println(Thread.currentThread().getName() + " arrived");
end.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
// 每个选手到达终点时,end就减一
}
}
}
class Statistics implements Runnable{
private HashMap<String,String> result;
Statistics(HashMap<String,String> result){
this.result=result;
}
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("Game Over\nbegin statistics:");
Iterator it=result.keySet().iterator();
while(it.hasNext()){
String key=(String)it.next();
String value=result.get(key);
System.out.println(key+":"+value);
}
}
}
结果
Game Start
player3 arrived
player4 arrived
player1 arrived
player6 arrived
player2 arrived
player0 arrived
player8 arrived
player7 arrived
player9 arrived
player5 arrived
Game Over
begin statistics:
player9:Mon Jun 06 21:15:26 CST 2016
player0:Mon Jun 06 21:15:22 CST 2016
player1:Mon Jun 06 21:15:20 CST 2016
player2:Mon Jun 06 21:15:22 CST 2016
player3:Mon Jun 06 21:15:17 CST 2016
player4:Mon Jun 06 21:15:18 CST 2016
player5:Mon Jun 06 21:15:27 CST 2016
player6:Mon Jun 06 21:15:21 CST 2016
player7:Mon Jun 06 21:15:25 CST 2016
player8:Mon Jun 06 21:15:22 CST 2016
其他同步辅助类:
Java并发编程-同步辅助类之Exchanger
Java并发编程-同步辅助类之Phaser
Java并发编程-同步辅助类之CountDownLatch
Java并发编程-同步辅助类之Semaphore