1、前言
体能状态先于精神状态,习惯先于决心,聚焦先于喜好。
2、栅栏的概念
栅栏类似于闭锁,它能阻塞 一组线程 直到某个事件发生。
栅栏最主要的目的在于,一组线程 准备就绪后,可以指定一个线程运行一个事件,然后其他线程可以继续执行。而闭锁就是门闩打开后各自可以继续运行。
3、CyclicBarrier——循环栅栏
CyclicBarrier 属于同步工具类,并且一个CyclicBarrier 对象可以循环使用;
顾名思义,循环栅栏,闭锁的计数器一旦递减为0就进入终态了,CyclicBarrier 也是基于计数器,但是其计数器在递减为0后,进行一次指定事件的运行后放行所有被其阻塞的线程后,计数器恢复为初始值,然后可以从新开始进行递减操作——阻塞相应的线程。
在子线程内调用 CyclicBarrier.await / c.await(2,TimeUnit.MINUTES);会使当前线程阻塞,直到 CyclicBarrier 的计数值为0,然后再继续运行线程剩余的逻辑。
CyclicBarrier 会阻塞一组线程,这一点很重要,如果你想在线程池中使用它,就需要考虑这种情况了——线程之间相互等待会降低线程池的使用效率。
CyclicBarrier 也可能会造成死锁,如果你的线程数不够,或者同时有两个或者以上的 CyclicBarrier 竞争有限的线程数,所以这种情况下c.await(2,TimeUnit.MINUTES); 更合适些。
CyclicBarrier 的初始化
CyclicBarrier 可以指定每组拦截的线程数
CyclicBarrier 支持指定 计数减为0时的事件——通过构造参数传参;也可以不指定任何操作。
private static CyclicBarrier cyclicBarrier =new CyclicBarrier(3,new Thread() {
@Override
public void run() {
super.run();
System.out.println(System.currentTimeMillis()+":满员喽,都坐稳当了,本次列车出发咯");
}
});
循环栅栏对象阻塞线程——可以增加阻塞时间限制
cyclicBarrier.await()是一个同步操作,极端情况下可能执行失败,为此我们可以增加一个时间条件,在超时时抛出异常——并且增加
- 不加限制的情况
cyclicBarrier.await();
- 增加限制的情况
c.await(2,TimeUnit.MINUTES);
场景
三人坐船到小岛种树,这个码头的小船只要有3个乘客就会出发。
代码
你可以试试把 3 变为 6后者 3n
for(int i=0;i<3;i++) {
for(int i=0;i<3n;i++) {
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierTest {
/**循环栅栏*/
private static CyclicBarrier c1=new CyclicBarrier(3,new Thread() {
@Override
public void run() {
super.run();
System.out.println(System.currentTimeMillis()+":乘务员:请大家系好安全带,即将出发");
}
});
public static void main(String[] args) {
//测试循环栅栏的效果
for(int i=1;i<=6;i++) {
Thread t=new Thread("name"+i) {
@Override
public void run() {
super.run();
try {
Thread.sleep(1000);
System.out.println(System.currentTimeMillis()+" "+Thread.currentThread().getName()+":已上车");
c1.await();
System.out.println(System.currentTimeMillis()+" "+Thread.currentThread().getName()+":系好安全带了");
} catch (InterruptedException | BrokenBarrierException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
t.start();
}
}
}
结果
1595124894805 name5:已上车
1595124894805 name3:已上车
1595124894805 name1:已上车
1595124894806:乘务员:请大家系好安全带,即将出发
1595124894806 name5:系好安全带了
1595124894807 name3:系好安全带了
1595124894806 name1:系好安全带了
1595124894809 name2:已上车
1595124894817 name4:已上车
1595124894817 name6:已上车
1595124894817:乘务员:请大家系好安全带,即将出发
1595124894817 name2:系好安全带了
1595124894818 name4:系好安全带了
1595124894818 name6:系好安全带了
参考资料
[1]、《Java 并发编程实战》