CyclicBarrier的源码分析

news2024/9/20 22:28:39

CyclicBarrier的源码分析

与CountDownLatch、Semaphore直接基于AQS实现不同,CyclicBarrier 是基于 ReentrantLock + ConditionObject 实现的,间接基于AQS实现的。

CyclicBarrier内部结构

  • Generation,静态内部类,持有布尔类型的属性broken,默认为false,只有在重置方法reset()、执行出现异常或中断调用breakBarrier() ,属性会被设置为true。
  • nextGenerate() 重置 CyclicBarrier 的计数器和generation属性。
  • breakBarrier() 任务执行中断、异常、被重置,将Generation中的布尔类型属性设置为true,将Waiter队列中的线程转移到AQS队列中,待执行完unlock方法后,唤醒AQS队列中的挂起线程。
  • await() :CyclicBarrier的核心方法,计数器递减处理。

构造函数

  构造参数重载,最终调用的是CyclicBarrier(int, Runnable),详情如下:

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

public CyclicBarrier(int parties, Runnable barrierAction) {
    // 参数合法性校验
    if (parties <= 0) throw new IllegalArgumentException();
    // final修饰,所有线程执行完成归为或重置时 使用
    this.parties = parties;
    // 在await方法中计数值,表示还有多少线程待执行await
    this.count = parties;
    // 当计数count为0时 ,执行此Runnnable,再唤醒被阻塞的线程
    this.barrierCommand = barrierAction;
}

CyclicBarrier属性

核心方法源码分析

await()

  在CyclicBarrier中,await有重载方法。await()表示会一直等待指定数量的线程未准备就绪(执行await方法);await(timout, unit)表示等待timeout时间后,指定数量的线程未准备就绪,抛出TimeoutException超时异常。

CyclicBarrier#await 详情如下:

// 执行没有超时时间的await
public int await() throws InterruptedException, BrokenBarrierException {
    try {
        // 执行dowait()
        return dowait(false, 0L);
    } catch (TimeoutException toe) {
        throw new Error(toe);
    }
}

// 执行有超时时间的await
public int await(long timeout, TimeUnit unit)
    throws InterruptedException,
           BrokenBarrierException,
           TimeoutException {
    return dowait(true, unit.toNanos(timeout));
}

await最终调用dowait()方法,CyclicBarrier#dowait 详情如下:

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

        // 这组线程被中断,重置标识与计数值,
        //     将Waiter队列中的线程转移到AQS队列,抛出InterruptedException
        if (Thread.interrupted()) {
            breakBarrier();
            throw new InterruptedException();
        }

        // 计数值 - 1
        int index = --count;
        // 这组线程都已准备就绪
        if (index == 0) {
            // 执行结果标识
            boolean ranAction = false;
            try {
                // 若使用2个参数的有参构造,就传入了自实现任务,index == 0,先执行CyclicBarrier有参的任务
                //     此处设计与 FutureTask 构造参数设计类似
                final Runnable command = barrierCommand;
                if (command != null)
                    // 执行任务
                    command.run();
                // 执行完成,设置为true
                ranAction = true;
                // CyclicBarrier属性归位
                nextGeneration();
                return 0;
            } finally {
                // 执行过程中出现问题
                if (!ranAction)
                    // 重置标识与计数值,将Waiter队列中的线程转移到AQS队列
                    breakBarrier();
            }
        }

        // -- 之后,count不为0,表示还有线程在等待
        // 自旋 直到被中断、超时、异常、count = 0
        for (;;) {
            try {
                // 未设置超时时间
                if (!timed)
                    // 挂起线程,将线程转移到 Condition 队列
                    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();
                }
            }

            // 该组线程被中断、执行异常、超时,抛出BrokenBarrierException异常
            if (g.broken)
                throw new BrokenBarrierException();

            if (g != generation)
                return index;

            // 超时,抛出异常TimeoutException
            if (timed && nanos <= 0L) {
                breakBarrier();
                throw new TimeoutException();
            }
        }
    } finally {
        // 释放锁资源
        lock.unlock();
    }
}

breakBarrier() - 结束CyclicBarrier的执行

// 结束CyclicBarrier的执行
private void breakBarrier() {
    // 设置线程执行过程中是否异常、中断、重置标识
    generation.broken = true;
    // 重置计数值
    count = parties;
    // 将Condition队列中的Node转移到AQS队列中,等到执行完unlock,AQS队列中的挂起线程会被唤醒
    // 有后继节点的,设置ws = -1;
    // 无后继节点的,设置ws = 0
    trip.signalAll();
}

reset() - 重置CyclicBarrier

// 重置CyclicBarrier
public void reset() {
    // 获取锁对象
    final ReentrantLock lock = this.lock;
    // 加锁
    lock.lock();
    try {
        // 设置当前generation属性,并将Waiter队列中线程转移到AQS队列
        breakBarrier();
        // 重置generation 属性、计数值
        nextGeneration();
    } finally {
        // 释放锁
        lock.unlock();
    }
}

nextGeneration() - CyclicBarrier归位

private void nextGeneration() {
    // 将Waiter队列中线程转移到AQS队列
    trip.signalAll();
    // 计数值、generation 归位
    count = parties;
    generation = new Generation();
}

总结

  CyclicBarrier基于 ReentrantLock + ConditionObject实现,CyclicBarrier的构造函数中必须指定parties,同时对象generation,内部持有布尔型属性表示当前CyclicBarrier执行过程中是否有超时、异常、中断的情况。

  parties是初始待执行线程数,在构造函数中会将parties赋给计数值count,每当一个线程执行await(),count就会减1。

  当count被减为0时,代表所有线程都准备就绪,此时判断构造函数是否初始化了barrierCommand属性,若对barrierCommand属性做了赋值,优先执行barrierCommand任务;

  barrierCommand任务执行完成,再将Waiter队列中的线程转移到AQS队列中,执行完unlock,唤醒AQS队列中的线程;计数值count、generation归位。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2139884.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一、机器学习算法与实践_01基本概念与项目流程笔记

0、机器学习基本概念 机器学习&#xff08;machine learning&#xff09;采用算法和统计模型&#xff0c;使计算机系统能够在大量数据中找到规律&#xff0c;然后使用能识别这些模式&#xff08;规律、趋势或结构&#xff09;的模型来预测或描述新的数据 1、机器学习相关术语 …

illustrator插件大全 免费插件介绍 Ai设计插件集合 (2)

12、Ai Toolbox 图层名称选择插件 支持AI CC2018-2022-2024 Ai Toolbox for Illustrator — Conical Labels, Bulk Rename and moreAi Toolbox is a plugin for Adobe Illustrator that makes conical labels, provides bulk artboards and paths renaming, selecting by name…

RK3568部署DOCKER启动服务器失败解决办法

按照上文的方法部署完DOCKER之后&#xff0c;启动服务异常&#xff0c;查阅网络相关资源&#xff0c;解决方案如下&#xff1a; 修改/源码/kernel/arch/arm64/configs/OK3568-C-linux_defconfig&#xff0c;在最后添加 CONFIG_MEMCGy CONFIG_VETHy CONFIG_BRIDGEy CONFIG_BRID…

Radware 报告 Web DDoS 攻击活动

新一代 HTTPS 洪水攻击的频率和强度急剧增加&#xff0c;攻击者引入的复杂程度也在迅速提高。2024 年上半年&#xff0c;Web 分布式拒绝服务 (DDoS) 攻击的频率和强度显著增加。其中很大一部分活动可以归因于受政治紧张局势驱使的黑客活动分子。 众所周知&#xff0c;当今的黑…

俄罗斯方块——C语言实践(Dev-Cpp)

目录 1、创建项目(尽量不使用中文路径) 2、项目复制 3、项目配置 ​1、调整编译器 2、在配置窗口选择参数标签 3、添加头文件路径和库文件路径 4、代码实现 4.1、main.c 4.2、draw.h 4.3、draw.c 4.4、shape.h 4.5、shape.c 4.6、board.h 4.7、board.c 4.8、cont…

ip映射域名,一般用于mysql和redis的固定映射,方便快捷打包

举个例子 192.168.3.101mysql映射到mysql.smartlink.com 192.168.3.101redis redis.smartlink.com 要将IP地址映射到域名&#xff0c;可以通过几种方式实现&#xff0c;包括修改本地主机文件&#xff08;仅适用于本地开发环境&#xff09;、设置DNS解析&#xff08;适用于生产环…

安卓玩机工具-----无需root权限 卸载 禁用 删除当前机型app应用 ADB玩机工具

ADB玩机工具 ADB AppControl是很实用的安卓手机应用管理工具&#xff0c;无需root权限&#xff0c;通过usb连接电脑后&#xff0c;可以很方便的进行应用程序安装与卸载&#xff0c;还支持提取手机应用apk文件到电脑上&#xff0c;此外还有手机系统垃圾清理、上传文件等…

Linus 强势拍板 6.11 合入: BPF 赋能调度器终成正果

本文地址&#xff1a;https://www.ebpf.top/post/bpf_sched_ext 1. 插拔调度器的萌芽【2004 年】 在 2004 年&#xff0c;Linux 社区的 Con Kolivas 提出了可插拔式调度器想法&#xff0c;旨在让内核中存在多个调度器&#xff0c;用户可在引导时选择。提交 patch 的工作原理是…

chapter14-集合——(List-Hashtable)——day18

目录 540-Hashtable使用 542-Properties 543-集合选型规则 544-TreeSet源码解读 546-Collections工具类 547-Collections工具类2 540-Hashtable使用 542-Properties 543-集合选型规则 544-TreeSet源码解读 这里讲错了,无参构造是默认调用添加对象的compareTo方法进行排序!…

南京工业大学《2020年+2021年820自动控制原理真题》 (完整版)

本文内容&#xff0c;全部选自自动化考研联盟的&#xff1a;《25届南京工业大学820自控考研资料》的真题篇。后续会持续更新更多学校&#xff0c;更多年份的真题&#xff0c;记得关注哦~ 目录 2020年真题 2021年真题 Part1&#xff1a;20202021年完整版真题 2020年真题 202…

CF 231 E Cactus 题解(仙人掌图上找环)

codeforces 提交记录 题意 有一个点仙人掌图&#xff08;每个点都只属于至多一个简单环&#xff09;&#xff0c;给出 k k k 个询问&#xff0c;问点 x x x 到点 y y y 有多少条简单路径&#xff08;经过的边不能重复&#xff0c;点可以&#xff09;。 思路 一看这个样例…

八、垃圾收集器G1ZGC详解

文章目录 G1收集器(-XX:UseG1GC)ZGC收集器(-XX:UseZGC)ZGC目标ZGC内存布局NUMA-awareZGC运作过程颜色指针颜色指针的三大优势读屏障ZGC存在的问题ZGC参数设置 如何选择垃圾收集器安全点与安全区域 G1收集器(-XX:UseG1GC) G1 (Garbage-First)是一款面向服务器的垃圾收集器,主要…

【开源分享】vsomeip 安装、编译、运行步骤笔记

文章目录 1. 摘要2. 安装、编译2.1 开发环境说明2.2 安装依赖2.3 获取代码2.4 编译代码2.5 安装 3. 测试验证参考 1. 摘要 本文主要描述 vsomeip 的安装、编译与运行步骤。下载源码&#xff0c;安装必要依赖&#xff0c;如Boost和CMake。通过CMake配置编译 vsomeip 库&#xf…

fpga系列 HDL:全连接层的浮点数乘法器FM实现

此代码实现了一个简单的浮点数乘法器&#xff0c;处理两个32位的单精度浮点数。它通过将两个浮点数的有效数字部分进行乘法操作&#xff0c;并对结果进行规范化以生成最终的浮点乘积。 主要逻辑与电路 去掉指数对齐部分后的主要逻辑电路图示&#xff1a; 代码 // https://…

海豚调度器DolphinScheduler--单机版DolphinScheduler 入门到实践:从部署到使用

Apache DolphinScheduler 是一个强大的分布式工作流任务调度系统&#xff0c;它以易用性和强大的功能在数据处理领域脱颖而出。本文将从部署到使用&#xff0c;详细介绍 DolphinScheduler 的各个方面&#xff0c;帮助您快速上手并有效利用这一工具。 一、DolphinScheduler 概述…

mac中git操作账号的删除

命令行玩的很溜的可以跳过 找到钥匙串访问 搜github、gitee就行了

k8s的NodeIP、PodIP、ClusterIP、ExternalIP

1.NodeIP K8s集群由Master Node与Worker Node组成。 Node&#xff1a;组成k8s集群的机器&#xff0c;可以是物理机或虚拟机。 Master Node &#xff1a;管理节点也叫控制平面主要负责管理控制方面。 Worker Node&#xff1a;&#xff1a;工作节点用于部署处理业务的工作负载或p…

【计算机网络】IP, 以太网, ARP, DNS

IP, 以太网, ARP, DNS IP协议回顾IP地址报文格式功能介绍地址管理IP地址数量问题初识 NAT 机制通信机制IP数量的解决方案网段划分特殊IP地址 路由选择 以太网协议报文格式源MAC/目的MACMAC地址是什么MAC地址格式MAC的作用 ARPDNS初识DNSDNS主要功能DNS的查询过程 IP协议 回顾I…

协同过滤算法商品推荐系统设计与实现

协同过滤算法商品推荐系统设计与实现 摘 要 传统办法管理信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行更改也比较困难&#xff0c;最后&#xff0c;检索数据费事费力。因此&#xff0c;在计算机上安装协同过滤算法商品推荐…

USB数据格式

文章目录 一、域、包、事务的概念1. **域&#xff08;Domain&#xff09;**2. **包&#xff08;Packet&#xff09;****包的类型**&#xff1a; 3. **事务&#xff08;Transaction&#xff09;****总结** 二、USB数据包格式1. **SOP&#xff08;Start of Packet&#xff09;**2…