JUC源码简析 CyclicBarrier

相关阅读

简介

CyclicBarrier表示可循环使用栅栏,即一个可循环利用的屏障,可以让所有线程彼此等待,直到所有线程都完成相应任务后,然后屏障前的所有线程才继续下一步动作;
内部持有的ReentrantLock的实例,保护屏障的入口;持有的Condition的实例,充当屏障;

和CountDownLatch的比较

  1. CountDownLatch是线程组之间的等待,即一个(或多个)线程等待其它N个线程完成相应任务后再执行下一步;而CyclicBarrier是线程组内的等待,即组内的每个线程相互等待,等都到达屏障,再执行下一步;
  2. CountDownLatch计数为0时无法重置,即无法循环使用;而CyclicBarrier计数达到初始值时,可以重置,即可以循环使用;

源码简析

内部类——Generation

private static class Generation {
    boolean broken = false;
}

维护等待线程的状态;

CyclicBarrier

构造方法

public CyclicBarrier(int parties, Runnable barrierAction) {
    // parties表示线程组中线程的个数,即要推倒栅栏(执行await方法)的线程个数,必须大于0
    if (parties <= 0) throw new IllegalArgumentException();
    this.parties = parties;
    this.count = parties;
    // 栅栏推倒后需要执行的任务,可以为null
    this.barrierCommand = barrierAction;
}

public CyclicBarrier(int parties) {
    this(parties, null);
}

nextGeneration

private void nextGeneration() {
    // 调用Condition的signalALL方法,唤醒所有等待线程
    trip.signalAll();
    // 重设count为parties
    count = parties;
    // 重设generation成员
    generation = new Generation();
}

本方法只能在持有锁的时候调用;

breakBarrier

private void breakBarrier() {
    // 设置generation状态为“推倒”
    generation.broken = true;
    // 重设count为parties
    count = parties;
    // 调用Condition的signalALL方法,唤醒所有等待线程
    trip.signalAll();
}

本方法只能在持有锁的时候调用;

dowait

private int dowait(boolean timed, long nanos)
    throws InterruptedException, BrokenBarrierException, TimeoutException {
    final ReentrantLock lock = this.lock;
    // 先上锁
    lock.lock();
    try {
        final Generation g = generation;
        if (g.broken)
            // 此时栅栏状态已经是“推倒”,则抛出BrokenBarrierException
            throw new BrokenBarrierException();

        // 如果当前线程发生过中断
        if (Thread.interrupted()) {
            // 调用breakBarrier推倒栅栏
            breakBarrier();
            // 抛出InterruptedException
            throw new InterruptedException();
        }

        int index = --count;
        // 如果栅栏的等待线程数量为0,说明最后一个线程达到栅栏,可以推倒栅栏了
        if (index == 0) {
            boolean ranAction = false;
            try {
                final Runnable command = barrierCommand;
                if (command != null)
                    // 推倒栅栏前有任务执行,则执行该任务
                    command.run();
                // 设置推倒栅栏成功标志为true
                ranAction = true;
                // 开启下一循环,可循环使用的体现
                nextGeneration();
                return 0;
            } finally {
                // 当执行推倒栅栏后的任务发生异常时进入
                if (!ranAction)
                    // 若还未推倒栅栏,则推倒栅栏
                    breakBarrier();
            }
        }

        // 死循环执行,确保本线程挂住,除非栅栏被推倒,或者本线程发生中断或者超时
        for (;;) {
            try {
                if (!timed)
                    // 不关心超时,则调用Condition.await释放锁资源,进行等待状态
                    trip.await();
                else if (nanos > 0L)
                    // 若关心超时,且超时时间大于0,则调用Condition.awaitNanos释放锁资源,同时设置了超时时间,进行等待状态等待
                    nanos = trip.awaitNanos(nanos);
            } catch (InterruptedException ie) {
                // 本线程在等待过程中发生中断异常

                // 如果当前栅栏信息没变化且栅栏还没被推倒
                if (g == generation && ! g.broken) {
                    // 推倒栅栏,因为等待发生中断,栅栏就失效了
                    breakBarrier();
                    // 继续抛出InterruptedException
                    throw ie;
                } else {
                    // 虽然本线程发生了中断,但栅栏信息已经变化
                    //     1. 变成新栅栏,本线程不属于新栅栏,不会对新栅栏有影响
                    //     2. 栅栏已被推倒,那么即使本线程未发生中断,也会被其它线程推倒栅栏时唤醒
                    // 所以此中断没啥作用,只需要重新设置中断标志即可
                    Thread.currentThread().interrupt();
                }
            }

            // 1. 可能是被其它推倒栅栏的线程调用signalAll唤醒;
            // 2. 可能是本线程发生中断异常唤醒;
            // 3. 可能是本线程设置超时时间,超时导致唤醒;
            // 4. 可能是本线程设置超时时间不大于0

            if (g.broken)
                // 如果记录的栅栏为“推倒”状态,则抛出BrokenBarrierException
                throw new BrokenBarrierException();

            if (g != generation)
                // 如果栅栏信息变化,则表示因为其它线程执行换代操作而唤醒本线程
                // 则直接返回原先记录的栅栏的等待线程数量(当前线程所在栅栏的下标)
                return index;

            if (timed && nanos <= 0L) {
                // 线程关心超时且发生了超时,则栅栏失效了
                
                // 推倒栅栏
                breakBarrier();
                // 抛出TimeoutException
                throw new TimeoutException();
            }
        }
    } finally {
        // finally代码块确保lock被释放
        lock.unlock();
    }
}

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));
}

isBroken

public boolean isBroken() {
    final ReentrantLock lock = this.lock;
    // 先上锁
    lock.lock();
    try {
        // 返回当前栅栏的状态
        return generation.broken;
    } finally {
        // finally代码块确保lock被释放
        lock.unlock();
    }
}

reset

public void reset() {
    final ReentrantLock lock = this.lock;
    // 先上锁
    lock.lock();
    try {
        // 推倒栅栏
        breakBarrier();
        // 开启新的栅栏
        nextGeneration();
    } finally {
        // finally代码块确保lock被释放
        lock.unlock();
    }
}

getNumberWaiting

public int getNumberWaiting() {
    final ReentrantLock lock = this.lock;
    // 先上锁
    lock.lock();
    try {
        return parties - count;
    } finally {
        // finally代码块确保lock被释放
        lock.unlock();
    }
}

测试

Demo

class Demo {
    private int parties = 5;
    private CyclicBarrier cyclicBarrier = new CyclicBarrier(5, new Runnable() {
        @Override
        public void run() {
            System.out.println("推倒栅栏");
        }
    });


    public static void main(String[] args) throws InterruptedException {
        Demo demo = new Demo();
        ExecutorService es = Executors.newFixedThreadPool(demo.parties);

        for (int i=0; i<demo.parties; i++) {
            es.execute(new CyclicBarrierTask(demo.cyclicBarrier));
        }

        es.shutdown();
    }


    private static class CyclicBarrierTask implements Runnable {

        private CyclicBarrier cb;


        CyclicBarrierTask(CyclicBarrier cb) {
            this.cb = cb;
        }

        @Override
        public void run() {
            int threadIndex = 0;
            try {
                TimeUnit.SECONDS.sleep(2);
                System.out.println(Thread.currentThread().getName() + " arrive to barrier at first time");
                threadIndex = cb.await();
                System.out.println(Thread.currentThread().getName() + " at index " + (cb.getParties()-threadIndex) + " of the barrier breaks barrier at first time");

                TimeUnit.SECONDS.sleep(2);

                System.out.println(Thread.currentThread().getName() + " arrive to barrier at twice time");
                threadIndex = cb.await();
                System.out.println(Thread.currentThread().getName() + " at index " + (cb.getParties()-threadIndex) + " of the barrier breaks barrier at twice time");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        }
    }
}

测试结果

pool-1-thread-2 arrive to barrier at first time
pool-1-thread-1 arrive to barrier at first time
pool-1-thread-4 arrive to barrier at first time
pool-1-thread-3 arrive to barrier at first time
pool-1-thread-5 arrive to barrier at first time
推倒栅栏
pool-1-thread-5 at index 5 of the barrier breaks barrier at first time
pool-1-thread-3 at index 4 of the barrier breaks barrier at first time
pool-1-thread-4 at index 3 of the barrier breaks barrier at first time
pool-1-thread-1 at index 2 of the barrier breaks barrier at first time
pool-1-thread-2 at index 1 of the barrier breaks barrier at first time
pool-1-thread-1 arrive to barrier at twice time
pool-1-thread-4 arrive to barrier at twice time
pool-1-thread-5 arrive to barrier at twice time
pool-1-thread-3 arrive to barrier at twice time
pool-1-thread-2 arrive to barrier at twice time
推倒栅栏
pool-1-thread-2 at index 5 of the barrier breaks barrier at twice time
pool-1-thread-4 at index 2 of the barrier breaks barrier at twice time
pool-1-thread-1 at index 1 of the barrier breaks barrier at twice time
pool-1-thread-5 at index 3 of the barrier breaks barrier at twice time
pool-1-thread-3 at index 4 of the barrier breaks barrier at twice time
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值