CyclicBarrier源码解析

CyclicBarrier也被称之为循环栅栏,是JUC中提供的一个同步工具类,用于解决某些需要指定现场到达某个屏障点才能继续执行后续操作的场景。

一个简单的demo示例。声明一个等待线程为5的栅栏,声明8个线程去执行,当第5个线程到达栅栏时,将会唤醒前4个等待的线程,这5个线程将执行自己的任务。CyclicBarrier将会开启下一代(新栅栏),剩余三个线程将会在新栅栏处等待,直到第5个线程到达将它们唤醒,可这里没有第5个线程,所以剩余三个线程将会一直等待。所以使用CyclicBarrier时需要对数量把控好。

	public static void testCyclicBarrier() throws InterruptedException {
        CyclicBarrier barrier = new CyclicBarrier(5, () -> {
            System.out.println("第一次都执行完成");
        });
        for (int i = 0; i < 8; i++) {
            final int k = i;
            new Thread(() -> {
                try {
                    Thread.sleep(3000 * (k));
                    //Thread.sleep(3000);
                    System.out.println("等待线程数" + barrier.getNumberWaiting());
                    barrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "执行完成");
            }).start();
        }
    }

demo已看完,接下来探讨探讨源码是怎么实现的。CyclicBarrier的源码相比同为栅栏的CountDownLatch要简单很多。两者实现完全不一样,CountDownLatch是基于AQS共享锁实现的,CyclicBarrier是基于Condition等待唤醒实现的。CyclicBarrier内部包含以下这些属性。

	// 同步锁
    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主要有以下两个构造函数。只指定栅栏等待线程数parties、指定栅栏换代前执行的任务。

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

CyclicBarrier中最主要的方法await()方法,和指定等待时间的await(long timeout, TimeUnit unit)方法,两者最终都是调用的dowait(boolean timed, long nanos)方法。

dowait方法,主要作用是通过计数器count,每一个线程调用该方法都会计数(减1),看是否有指定线程数到达栅栏处,当计数器为0时意味着有指定线程到达栅栏,则唤醒等待的线程并开启下一个栅栏。否则会等待直到被唤醒。

	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)
                // 只有在breakBarrier()方法调用时才会破坏当前代
                throw new BrokenBarrierException();

            // 如果当前线程中断了 则破坏当前代 并抛异常
            if (Thread.interrupted()) {
                breakBarrier();
                throw new InterruptedException();
            }

            // 当前代到达线程数量减一  当到达线程数量达到指定数量时 则会开启下一代(放开栅栏,重新下一次等待)
            int index = --count;
            if (index == 0) {  // tripped
                // 指定函数执行成功标志
                boolean ranAction = false;
                try {
                    // 构造函数时 声明的一个在达到一次开启栅栏时执行的任务
                    final Runnable command = barrierCommand;
                    if (command != null)
                        command.run();
                    // 任务执行成功
                    ranAction = true;
                    // 开启下一代  唤醒等待的线程
                    nextGeneration();
                    return 0;
                } finally {
                    if (!ranAction)
                        // 如果指定任务执行失败 则破坏当前代
                        breakBarrier();
                }
            }

            // loop until tripped, broken, interrupted, or timed out
            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 {
                        // We're about to finish waiting even if we had not
                        // been interrupted, so this interrupt is deemed to
                        // "belong" to subsequent execution.
                        Thread.currentThread().interrupt();
                    }
                }

                // 线程被唤醒 或者中断异常 或者等待指定时间已过被唤醒 则走下面

                // 如果当前代被破坏 抛异常
                if (g.broken)
                    throw new BrokenBarrierException();

                // 如果已经不是当前代了(已经换代成功) 则结束循环
                if (g != generation)
                    return index;

                // 如果指定了时间 并且指定时间已过 被唤醒 则破坏当前代 并抛异常
                if (timed && nanos <= 0L) {
                    breakBarrier();
                    throw new TimeoutException();
                }
            }
        } finally {
            lock.unlock();
        }
    }

开启下一代方法主要作用是所有等待的线程。并充值计数器,重新开启下一代。

	private void nextGeneration() {
        // 唤醒所有等待的线程
        trip.signalAll();
        // 重置计数器
        count = parties;
        // 重置新一代  (重置是否破坏标志)
        generation = new Generation();
    }

破坏栅栏方法主要将当前代标记为已破坏,并唤醒所有线程,充值计数器。

	private void breakBarrier() {
        // 设置当前代为已破坏
        generation.broken = true;
        // 重置计数器
        count = parties;
        // 唤醒所有线程
        trip.signalAll();
    }

CyclicBarrier还提供了几个方法供外部调用以获取内部一些状态。

获取正在等待的线程数量。

	// 获取当前正在栅栏处等待的线程
    public int getNumberWaiting() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            return parties - count;
        } finally {
            lock.unlock();
        }
    }

查看当前代是否被破坏。

/**
     * 返回当前代是否被破坏
     * @return
     */
    public boolean isBroken() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            return generation.broken;
        } finally {
            lock.unlock();
        }
    }

重置栅栏。

	public void reset() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            // 破坏当前代
            breakBarrier();   // break the current generation
            // 开启下一代
            nextGeneration(); // start a new generation
        } finally {
            lock.unlock();
        }
    }

这类的文章网上虽然很多,但还是决定自己写一下,毕竟好记性不如烂笔头,自己写的终归有助于自己记忆。但是终究是没有别人的图文并茂来的好。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智慧校园建设是在国家政策推动下,为深化教育改革、提升教育质量和管理效率而提出的重要项目。该项目旨在通过信息化手段,解决传统教育中存在的资源分散、管理混乱等问题,实现教育资源的高效利用和教学质量的全面提升。 目前,教育信息化虽取得一定进展,但面临“孤岛架构”的挑战,包括硬件资源无法共享、数据孤岛、应用孤岛等问题,导致资源浪费和管理效率低下。为此,智慧校园的建设目标聚焦于家校沟通便捷化、校园管理科学化、校园生活轻松化、课堂教学互动化和校园设施智能化,以提高教学效率和学生学习体验。 智慧校园的核心价值在于构建先进的网络教学平台和管理信息系统,实现教学资源的高效配置和利用,促进师生互动,提高管理效率,降低成本,构建健康高雅的生活环境。解决方案涵盖综合应用平台规划、系统架构设计、媒体发布、数字会议系统等,通过后台服务层、基础接入层和用户接入层的有机结合,实现智慧校园的全面功能。 智慧校园管理平台作为核心组成部分,提供模块化体系,包括公开课、直播、教学资源等23大应用,支持与第三方接口对接,实现多级管理。电教预约管理平台通过移动端APP或web后台简化预约流程,提高教室和会议室资源利用率,支持会议预订、审批、信息发布和环境管控。 教育录播系统和云平台支持教师制作和分享优质教学资源,进行在线组卷和评卷,同时提供学生应用,如高清视频录制、在线直播和互动交流,促进教学资源的共享和教育均衡化发展。这些系统的整合应用,将极大地推动教育信息化进程,实现教育资源的最大化利用和教育质量的全面提升。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值