最近这两周有点小忙,唉……
前面两篇介绍了基于AQS的两个并发工具类CountDownLatch和Semaphore。今晚的CyclicBarrier也是工具类之一,但内部并没使用AQS来实现。
简介
Cyclic意思是循环,Barrier意思是屏障,那么CyclicBarrier翻译过来就是循环栅栏。它是一个同步辅助类,能让一组线程互相等待,直到这一组线程都到了一个公共屏障点,各线程才能继续向下执行。因为该屏障能够在释放等待线程后继续重用,所以叫循环屏障。
构造方法
内部属性
public class CyclicBarrier {
private static class Generation {
boolean broken = false;
}
private final ReentrantLock lock = new ReentrantLock();
private final Condition trip = lock.newCondition();
private final int parties;
private final Runnable barrierCommand;
private Generation generation = new Generation();
private int count;
}
CyclicBarrier内部是使用独占锁实现的。CyclicBarrier常用的方法列表如下:
await()是最常用的,在所有线程都已经在这个CyclicBarrier上调用await()之前,将一直等待。
简单示例
今晚我们小组拿着公费出去吃饭了,小组一共五个人,假设我们组有个死规矩,就是人不到齐不动筷子,大家能不能早点吃上饭就看最后一个人啥时候来。。
/**
* Created by bxw on 2017/10/31.
*/
public class CyclicBarrierTest {
//小组5个人
private static CyclicBarrier cyclicBarrier = new CyclicBarrier(5);
public static class Thread1 extends Thread{
public Thread1(String name) {
super(name);
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "入座了");
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "开始吃饭了");
}
}
public static void main(String[] args) {
//五个人依次进入饭店
for(int i = 0; i < 5; i++){
new Thread1("码农"+i+"号").start();
}
}
}
运行结果:
不巧,今天有个人请假了不在,但这次吃饭的意义是团建,需要让他过来一起吃,死规矩还是一样,人不来齐不动筷子,但请假的一时半会过不来,只有四个人依次进入了饭店。修改上面代码的main函数
public static void main(String[] args) {
//五个人依次进入饭店
for(int i = 0; i < 4; i++){
new Thread1("码农"+i+"号").start();
}
}
运行结果:
最近吃饭又多了一个规矩,小组成员来齐后,吃饭之前,组长需要先咳咳两声,讲两句,话讲完后才能开始吃,这时候就需要在构造barrier时指定一个barrierAction。
/**
* Created by bxw on 2017/10/31.
*/
public class CyclicBarrierTest {
//小组5个人
private static CyclicBarrier cyclicBarrier = new CyclicBarrier(5, new Runnable() {
@Override
public void run() {
System.out.println("组长讲话:大家最近辛苦了,来,倒满,先走一个……");
}
});
public static class Thread1 extends Thread{
public Thread1(String name) {
super(name);
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "入座了");
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "开始吃饭了");
}
}
public static void main(String[] args) {
//五个人依次进入饭店
for(int i = 0; i < 5; i++){
new Thread1("码农"+i+"号").start();
}
}
}
运行结果:
CyclicBarrier与CountDownLatch的区别:
①CyclicBarrier主要用于一组线程之间的相互等待,而CountDownLatch一般用于一组线程等待另一组些线程。比如在上上篇<并发工具类CountDownLatch>中举的火锅例子中,是服务员线程在等三个消费者线程消费完毕后才执行收拾桌子的任务。而本篇CyclicBarrier的吃饭例子中是各组员之间相互等待。
②在所有线程到达集合点后接受一个Runnable类型的对象作为后续的执行。
③CycliBarrier对象可以重复使用,重用之前应当调用CyclicBarrier对象的reset方法。
总结
本篇简单介绍了并发工具类CyclicBarrier,能够让一组线程相互等待,只有这一组线程全部到达了屏障点,这组线程才会继续执行,对于一些线程并行执行和结果统计的场景上能派上用场(遗憾的是本人在工作中暂未使用过)。与CountDowch的主要区别是CountDownLatch是一组线程等另一组线程执行,CyclicBarrier是一组线程相互等待。