5.2、多线程学习——栅栏的一个实现 CyclicBarrier

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<3
n;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 并发编程实战》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值