承接上一篇。多线程-并发:介绍CountDownLatch
本文依然以《天龙八部》四大恶人举例。
纵览整本小说,四大恶人为了准备杀段正淳集结在大理,为了歼灭丐帮集结在杏子林,为了少室山大战集结在少室山....
我们发现,四大恶人仅仅一次集合是不够的!也就是说,这“四个线程”仅仅并发协作一次不够的!
但是CountDownLatch却是一次性的并发工具。由此,CyclicBarrier有了勇武之地。
/*
CyclicBarrier循环屏障
用途:协同指定数目的线程,让这些线程在这个屏障前等待,知道所有线程都到达了这个屏障,在一起继续执行。线程继续执行后,这个屏障可再次使用,因此为循环屏障。
*/
public class CyclicBarrier {
//构造方法
//parties:制定多有少个部分(线程)参与,被称为参与数。
public CyclicBarrier(int parties){...}
//构造方法
/*
barrierAction:所有参与者都达到屏障时执行的一次的命令,在一组线程中的最后一个线程达到之后(但在释放所有线程之前),在该线程中执行该命令,该命令只在每个屏障点运行一次。若要在继续执行所有参与线程之前更新共享状态,此屏障操作很有用!
*/
public CyclicBarrier(int parties , Runnable barrierAction){...}
//等待方法
/*
线程执行过程中调用await()方法,表明自己已达到屏障,自己阻塞,等待其他线程到达屏障;所有参与线程都到达屏障,即等待线程数==参与者,则释放所有线程,让他们继续执行。
返回int值是到达的当前线程的索引号,注意索引号是从parties-1开始递减到0。
BrokenBarrierExcepyion:屏障被破坏异常,当调用await时,或等待过程中屏障被破坏,则会抛出该异常。
*/
public int await() throws InterruptedException, BrokenBarrierException {...}
//以下方法不做重点讨论
//等待指定时长,如到了时间还不能释放,则将抛出TimeoutException
public int await(long timeout, TimeUnit unit)
throws InterruptedException,
BrokenBarrierException,
TimeoutException {...}
//获取当前等在屏障处的线程数
public int getNumberWaiting() {}
//判断线程是否被破坏
public boolean isBroken() {}
//重置屏障为初始状态。如果当前有线程正在等待,则这些线程将被释放并抛出BrokenBarrierException
public void reset() {}
}
CyclicBarrier使用注意事项:
一定要保证有足够的参与者线程,否则会一直被阻塞在屏障处。
在线程池中使用要更加小心!确保池的线程数>=要求的参与数
CyclicBarrier适用场景:
等待一起出发。
多次等待一起出发。
CyclicBarrier cyclicBarrier = new CyclicBarrier(4);
for(int i = 0 ; i < 4 ; i++) {
new Thread((i + 1) + ""){
@Override
public void run() {
System.out.println("大理城天下第" + this.getName() + "大恶人到了");
cyclicBarrier.await();
System.out.println("杏子林天下第" + this.getName() + "大恶人到了");
cyclicBarrier.await();
System.out.println("少室山天下第" + this.getName() + "大恶人到了");
}
}.start();
}
注:为了美观await()方法没有加try-catch
CyclicBarrier和CountDownLatch的区别:
CountDownLatch:是一部分线程等待另一部分线程来唤醒。
CyclicBarrier:是参与线程彼此等待,都到达了,在一起继续。
CountDownLatch不可循环使用,都到达了,在一起继续。