【源码】JUC —— CyclicBarrier 浅析

【源码】JUC —— CyclicBarrier 浅析

前言

CyclicBarrierCountDownLatchplus 版。在 CountDownLatch 的基础上,允许

  • 循环使用,指定数量的线程被唤醒后,将再次进入下一轮阻塞、唤醒
  • 允许指定一个 Runnable,在唤醒阻塞线程前执行

CountDownLatch 略有不同的是,不用显示的“倒计时”,而是在阻塞线程数达到 阈值 时直接唤醒该批线程

关于 CountDownLatch ,可阅读

【源码】JUC —— CountDownLatch 浅析

JDK 版本

JDK11

CyclicBarrier

	// 内部由 ReentrantLock 保证线程安全
	private final ReentrantLock lock = new ReentrantLock();
    
    // 用于阻塞的 Condition 
    private final Condition trip = lock.newCondition();
    
    // 阻塞阈值
    private final int parties;
    
    // 唤醒线程前执行的任务
    private final Runnable barrierCommand;
    
    // 每个批次以 Generation 划分
    private Generation generation = new Generation();

	// 每个 Generation 的具体阈值
    private int count;

	// 内部类 Generation
	private static class Generation {
        Generation() {} 
        boolean broken;                 
    }

	public CyclicBarrier(int parties, Runnable barrierAction) {
        if (parties <= 0) throw new IllegalArgumentException();
        this.parties = parties;
        this.count = parties;
        this.barrierCommand = barrierAction;
    }

	// barrierAction 当然也可以为 null
    public CyclicBarrier(int parties) {
        this(parties, null);
    }

    public int getParties() {
        return parties;
    }

CyclicBarrier属性构造方法

await

	public int await() throws InterruptedException, BrokenBarrierException {
        try {
            return dowait(false, 0L);
        } catch (TimeoutException toe) {
            throw new Error(toe); 
        }
    }

    public int await(long timeout, TimeUnit unit)
        throws InterruptedException,
               BrokenBarrierException,
               TimeoutException {
        return dowait(true, unit.toNanos(timeout));
    }

	private int dowait(boolean timed, long nanos)
        throws InterruptedException, BrokenBarrierException,
               TimeoutException {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            // 当前 Generation
            final Generation g = generation;

            if (g.broken)
                throw new BrokenBarrierException();

            // 响应中断
            if (Thread.interrupted()) {
                breakBarrier();
                throw new InterruptedException();
            }

            /**
             * 阈值递减
             * 当阈值到 0 时,执行指定任务(如果存在)
             * 并开始下一轮 Generation
             */
            int index = --count;
            if (index == 0) {  
                boolean ranAction = false;
                try {
                    final Runnable command = barrierCommand;
                    if (command != null)
                        command.run();
                    ranAction = true;
                    nextGeneration();
                    return 0;
                } finally {
                    if (!ranAction)
                        breakBarrier();
                }
            }

            // 否则阻塞当前线程
            for (;;) {
                try {
                    if (!timed)
                        trip.await();
                    else if (nanos > 0L)
                    	// 支持限时
                        nanos = trip.awaitNanos(nanos);
                } catch (InterruptedException ie) {
                    if (g == generation && ! g.broken) {
                        breakBarrier();
                        throw ie;
                    } else {
                        Thread.currentThread().interrupt();
                    }
                }

                if (g.broken)
                    throw new BrokenBarrierException();

                if (g != generation)
                    return index;

				// 如果超时则中止当前 Generation 并抛出 TimeoutException
                if (timed && nanos <= 0L) {
                    breakBarrier();
                    throw new TimeoutException();
                }
            }
        } finally {
            lock.unlock();
        }
    }

	// 开始新一轮 generation
    private void nextGeneration() {
        // 唤醒所有阻塞线程
        trip.signalAll();

        // 重置阈值
        count = parties;
        
        // 新的 generation
        generation = new Generation();
    }

	// 中止当前 generation
    private void breakBarrier() {
        // 设置标识位
        generation.broken = true;

        // 重置阈值
        count = parties;

        // 唤醒所有阻塞线程
        trip.signalAll();
    }

调用 await 方法阻塞线程,当到达 阈值 后唤醒所有线程并开启下一轮。中断超时 等会导致本轮 generation 中止

其他

	// 当前 generation 是否中止
    public boolean isBroken() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            return generation.broken;
        } finally {
            lock.unlock();
        }
    }

	// 重置 Generation(中止后开启新一代)
    public void reset() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            breakBarrier();   // break the current generation
            nextGeneration(); // start a new generation
        } finally {
            lock.unlock();
        }
    }

	// 当前阻塞的线程数
    public int getNumberWaiting() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            return parties - count;
        } finally {
            lock.unlock();
        }
    }

同样提供了 generation重置 方法,以及 中止情况查看阻塞线程数查看 的相关方法

demo

public class CyclicBarrierTest {
    public static void main(String[] args) throws BrokenBarrierException, InterruptedException {
        CyclicBarrier cyclicBarrier =
                new CyclicBarrier(3, () -> System.out.println("boom"));

        while (true) {
            new Thread(() -> {
                System.out.print("di ");
                try {
                    cyclicBarrier.await();

                    // 超时而导致 TimeoutException
                    // cyclicBarrier.await(1, TimeUnit.SECONDS);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                /*} catch (TimeoutException e) {
                    e.printStackTrace();*/
                }
                System.out.print(".");
            }).start();
            TimeUnit.SECONDS.sleep(1);

        }
    }
}

结果:
di di di boom
...di di di boom
...di di di boom
...

定时炸弹

总结

很好用的一个类,可以看作是 CountDownLatch 的升级版~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值