LongAdder 和 Striped64 基础学习

cs,表示 Cell 数组的引用;b,表示获取的 base 值,类似于 AtomicLong 中全局变量的 value 值,在没有竞争的情况下数据直接累加到 base 上,或者扩容时,也需要将数据写入到 base 上;v,表示期望值;m,表示 Cell 数组的长度;a,表示 当前线程命中的 cell 表格。

public void add(long x) {Cell[] cs; long b, v; int m; Cell c;// 首次首线程 ((cs = cells) != null) 一定是false;此时走 casBase(long cmp, long val) 方法,当且仅当 cas 失败的时候,才会走到 if 中。if ((cs = cells) != null || !casBase(b = base, b + x)) {// getProbe(); 的返回的是线程中 threadLocalRandomProbe 字段,它是通过一个随机数字段,对于一个特定的线程这个值是固定的(除非刻意修改它)int index = getProbe();// true,无竞争;false,表示竞争激烈,多个线程 hash 到同一个 Cell,可能需要扩容boolean uncontended = true;// 条件一:Cell[] 为 null// 条件二:一般不会出现// 条件三:当前线程所在的 cell 为空,说明当前线程还没有更新过 Cell,应初始化一个 Cell// 条件四:更新当前线程所在的 cell 失败,说明现在竞争很激烈,多个线程 hash 到了同一个 Cell,应扩容if (cs == null || (m = cs.length - 1) < 0 ||(c = cs[index & m]) == null ||!(uncontended = c.cas(v = c.value, v + x)))// longAccumulate(long x, LongBinaryOperator fn, boolean wasUncontended, int index)longAccumulate(x, null, uncontended, index); // x,一般默认都是1;fn,默认是 null,uncontended,如果是第四个条件,那就是false。}
}
final void longAccumulate(long x, LongBinaryOperator fn,boolean wasUncontended, int index) {if (index == 0) {// 如果 index 是0,那就强制为当前线程初始化ThreadLocalRandom.current(); // force initialization// getProbe(); 获取当前线程的 hash 值index = getProbe();wasUncontended = true; // true,表示无竞争,重新计算了当前线程的 hash 值后认为此次不算是一次竞争,因为都还没有进行初始化,肯定还不存在竞争激烈}// collide 表示扩容意向,false 表示一定不会扩容, true 表示可能会扩容for (boolean collide = false;;) {       // True if last slot nonemptyCell[] cs; Cell c; int n; long v;// 第一种情况:Cell[] 数组已经被初始化了if ((cs = cells) != null && (n = cs.length) > 0) {// 当前前程的 hash 值运算后映射得到的 Cell 单元为 null,说明该 cell 没有被使用过if ((c = cs[(n - 1) & index]) == null) {// cellsBusy,初始化 cells,或者扩容 cells 需要获取锁。0,表示无锁状态。1,表示其他线程已经持有了锁。if (cellsBusy == 0) {       // Try to attach new CellCell r = new Cell(x);   // Optimistically create// casCellsBusy(),通过 cas 操作修改 cellsBusy 的值,cas 成功代表获取锁,返回 true// 尝试加锁,成功后 cellsBusy = 1if (cellsBusy == 0 && casCellsBusy()) {try {               // Recheck under lockCell[] rs; int m, j;// 在有锁的情况下再检测一遍之前的判断if ((rs = cells) != null &&(m = rs.length) > 0 &&rs[j = (m - 1) & index] == null) {rs[j] = r; // 将 Cell 添加到 Cell[] 数组中break;}} finally {cellsBusy = 0;}continue;           // Slot is now non-empty}}collide = false;}// 这个分支,表示我竞争失败了,将 wasUncontended = true; 执行 index = advanceProbe(index); 重新竞争else if (!wasUncontended)       // CAS already known to failwasUncontended = true;      // Continue after rehashelse if (c.cas(v = c.value,(fn == null) ? v + x : fn.applyAsLong(v, x)))break;// NCPU,当前计算机 CPU 的个数,Cell 数组扩容时会用到else if (n >= NCPU || cells != cs) // 如果 n = cs.length 大于了 CPU 的数量或者 cells 和我们的 cs 不是同一个,那就别扩容了collide = false;            // At max size or staleelse if (!collide)collide = true;else if (cellsBusy == 0 && casCellsBusy()) {try {// 当前的 cells 数组和最先赋值的cs是同一个,代表没有被其他线程扩容过if (cells == cs)        // Expand table unless stalecells = Arrays.copyOf(cs, n << 1); // 按位左移1位,相当于扩大为原来大小的两倍,扩容后再将原先的数组元素拷贝到新数组中} finally {cellsBusy = 0; // 释放锁}collide = false;continue;                   // Retry with expanded table}// advanceProbe(index); 重置当前线程的 hash 值index = advanceProbe(index);}// 第二种情况:Cell[] 数组还没有进行初始化,尝试对它加锁,并首次 Cell[] 数组初始化else if (cellsBusy == 0 && cells == cs && casCellsBusy()) {try {                           // Initialize tableif (cells == cs) {Cell[] rs = new Cell[2];rs[index & 1] = new Cell(x);cells = rs;break;}} finally {cellsBusy = 0;}}// 第三种情况:Cell[] 数组正在进行初始化的时候(第二步还没有完成,其他线程来了),则尝试直接在基数 base 上进行累加操作,兜底的操作// Fall back on using baseelse if (casBase(v = base,(fn == null) ? v + x : fn.applyAsLong(v, x)))break;}
}

double check

static final int getProbe() {return (int) THREAD_PROBE.get(Thread.currentThread());}

看下里面的 THREAD_PROBE,在 jdk8 中用的是 UNSAFE 类,这里是 MethodHandles.lookup()。

MethodHandles.Lookup l = MethodHandles.lookup();
THREAD_PROBE = l.findVarHandle(Thread.class, "threadLocalRandomProbe", int.class);

左移(<<)规则:符号位不变,高位溢出截断,低位补零。比如 -1 << 2 = -4 (为方便讲解,图示的补码为-1)
左移位运算
位运算规则:

Java数值运算过程中都是先将十进制转换为二进制然后再进行运算,再把二进制数据转换为十进制展现给用户。二进制运算规则如下:
1、对于有符号的而言,最高位为符号位,0表示正数,1表示负数。
2、正数的原码,反码和补码都一样,三码合一。
3、负数的反码:符号位保持不限,其他位取反,负数的补码:补码 + 1。
4、0的反码和补码都是0。

下面以 -1 为例子展示原码、反码和补码的转换关系(以int数据类型为例,int类型在Java中占4字节):
原码、反码和补码的关系

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

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

相关文章

Linux第2课Windows下的环境配置-虚拟机安装

文章目录 Linux第2课Windows下的环境配置-虚拟机安装一、VMware虚拟机的安装&#xff08;一&#xff09;安装VMware&#xff08;二&#xff09;启动电脑本地的VMware相关服务 二、VirtualBox安装 Linux第2课Windows下的环境配置-虚拟机安装 本节课程提供了两种虚拟机的安装方法…

个人医疗开支预测项目

注意&#xff1a;本文引用自专业人工智能社区Venus AI 更多AI知识请参考原站 &#xff08;[www.aideeplearning.cn]&#xff09; 项目背景 随着医疗成本的持续上涨&#xff0c;个人医疗开支成为一个重要议题。理解影响医疗费用的多种因素对于医疗保险公司、政府机构以及个人…

磁环的使用方法

磁环的使用方法 磁环的工作原理共模滤波用法差模滤波用法各种材料磁环的对应频率磁环的感量计算 磁环的工作原理 共模滤波用法 差模滤波用法 各种材料磁环的对应频率 磁环的感量计算

Redis从入门到精通(四)Redis实战(二)商户查询缓存

↑↑↑请在文章头部下载测试项目原代码↑↑↑ 文章目录 前言4.2 商户查询缓存4.2.1 缓存介绍4.2.2 查询商户信息的传统做法4.2.2.1 接口文档4.2.2.2 代码实现4.2.2.3 功能测试 4.2.3 查询商户信息添加Redis缓存4.2.3.1 逻辑分析4.2.3.2 代码实现4.2.3.3 功能测试 4.2.3 数据一致…

【MATLAB源码-第177期】基于matlab的蜘蛛蜂优化算法(SWO)无人机三维路径规划,输出做短路径图和适应度曲线

操作环境&#xff1a; MATLAB 2022a 1、算法描述 蜘蛛蜂优化算法&#xff08;Spider Wasp Optimization, SWO&#xff09;是一种启发式算法&#xff0c;它受到自然界中蜘蛛和蜂这两种生物的行为模式启发而开发。这一算法主要模拟了蜘蛛捕食与蜂群社会行为之间的相互作用&…

网络以太网之(1)基础概念

网络以太网之(1)基础概念 Author: Once Day Date: 2024年4月1日 一位热衷于Linux学习和开发的菜鸟&#xff0c;试图谱写一场冒险之旅&#xff0c;也许终点只是一场白日梦… 漫漫长路&#xff0c;有人对你微笑过嘛… 全系列文档可参考专栏&#xff1a;通信网络技术_Once-Day的…

C语言-----数据在内存中的存储(1)

1.整数在内存中的存储 我们之前就了解过整数的二进制写法分别有3种&#xff0c;分别为原码&#xff0c;反码&#xff0c;补码。整型在内存中存储的是补码。 原码&#xff0c;反码&#xff0c;补码都有自己的符号位和数值位&#xff0c;符号位为1时&#xff0c;则表示负数&…

【Docker笔记05】【网络模式】

一、前言 本系列是根据 B 站 尚硅谷 Docker 视频 学习记录笔记。因为没有视频课件&#xff0c;部分内容摘自 https://www.yuque.com/tmfl/cloud/dketq0。 本系列仅为自身学习笔记记录使用&#xff0c;记录存在偏差&#xff0c;推荐阅读原视频内容或本文参考笔记。 二、简单介…

通用开发技能系列:Authentication、OAuth、JWT 认证策略

云原生学习路线导航页&#xff08;持续更新中&#xff09; 本文是 通用开发技能系列 文章&#xff0c;主要对编程通用技能 Authentication、OAuth、JWT 认证策略 进行学习 1.Basic Authentication认证 每个请求都需要将 用户名密码 进行base64编码后&#xff0c;放在请求头的A…

基于隐私保护的可追踪可撤销密文策略属性加密方案论文阅读

论文是2022年发表的A Traceable and Revocable Ciphertext-Policy Attribute-based Encryption Scheme Based on Privacy Protection 摘要 本篇论文提出了一种具有用户撤销、白盒追踪、策略策略隐藏功能的CP-ABE方案。在该方案中密文被分为两个部分&#xff1a;第一个部分是和…

基于springboot实现教师人事档案管理系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现在线商城系统演示 摘要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本ONLY在线商城系统就是在这样的大环境下诞生&#xff0c;其可以帮助管理…

第六期丨酷雷曼无人机技能培训

第6期无人机技能提升培训 盼望着盼望着&#xff0c;第六期无人机技能提升培训会终于如期和大家见面了。 2024年1月1日&#xff0c;国务院、中央军事委员会颁布《无人驾驶航空器飞行管理暂行条例》&#xff0c;对民用无人机飞行活动实施更为严格的规范约束&#xff0c;越来越多…

阿里云服务器安装Java开发环境最佳实践

服务器环境安装 环境依赖服务器配置配置SSH登录打开安全配置端口远程连接配置秘钥 Linux服务器常用指令向远程服务器传送文件systemctl 相关 安装MySql安装步骤step1 检查并清除以前的mysql相关文件step2 安装step3 MySQL参数配置step4 设置开机启动step5 初始化数据库step6配置…

ABAP开发中常用弹窗的应用详解

在ABAP程序设计中为提示和交互的需要会经常用到弹窗&#xff0c; 所谓弹窗就是弹出一个框&#xff0c;告诉用户什么事情、需要确认什么、或者让用户输入什么内容等等&#xff0c;它价值在于通过提示、提醒、警告&#xff0c;帮助用户顺利完成业务流程中的必要操作或给用户提供实…

【JS】打乱数组顺序,用作领域:随机播放音乐

思路 循环数组随机获取数组下标取值&#xff1a; 取当前随机下标数组取当前循环的下标数组 相互替换步骤3的数组 /*** 随机数组顺序* param {Array} arr 数组* returns Array*/ const shufArr arr > {for (let i arr.length - 1; i > 0; i--) {const j Math.floor(M…

中国智慧城管哪家做的好?

智慧城市管理综合执法系统建立全市统一的法律法规、裁量基准、执法事项、执法文书和基础信息库&#xff0c;实现从获取线索、立案、调查、处理到结案全过程的信息化和文书制作的智能化。全面支持移动执法办案&#xff0c;提高执法效率。 技术架构&#xff1a; 微服务javasprin…

中颖51芯片学习1. 系统时钟及IO口输出操作

中颖51芯片学习1. 系统时钟及IO口输出操作 一、芯片介绍1. 规格2. 资源3. 中断源&#xff1a;4. 方框图5. 封装&#xff08;1&#xff09;32脚LQFP封装&#xff08;2&#xff09;28脚SOP封装&#xff08;3&#xff09;20脚SOP封装 二、开发环境搭建1. 安装keil2. 安装中颖keil插…

安全测试重点思考(中)--如何防止漏洞XSS和CSRF漏洞

如何防止漏洞XSS和CSRF漏洞 XSS漏洞的预防springsecurity框架来预防xss漏洞的步骤将特殊字符进行实体转义使用类库和修改cookie属性使用安全的HTTP Only Cookie使用安全的Cookie使用CSP&#xff08;内容安全策略&#xff09;使用专门的XSS防护库输入验证和过滤 XSS的面试题你对…

4.2总结

了解了部分Api的使用并学习了接口的API API API包含了较多种类&#xff08;System,Runtime等&#xff09; System其实就是一个工具类&#xff0c;提供了一些与系统相关的方法 下面有一些常间的System方法 方法名说明public static void exit (int status)终止当前运行的ja…

深入浅出 -- 系统架构之微服务架构常见的六种设计模式

面向服务的架构&#xff08;SOA&#xff09; 面向服务的架构&#xff08;SOA&#xff09;是一种设计方法&#xff0c;也是一个组件模型&#xff0c;它将应用程序的不同功能单元&#xff08;称为服务&#xff09;通过这些服务之间定义良好的接口和契约联系起来。接口是采用中立的…