一文搞懂CAS实现原理——怀玉
点个关注,必回关
文章目录
- CAS原理剖析
- 1、参数
- 解密CAS底层指令
CAS(Compare and swap)是一种用于在多线程环境下实现同步功能的机制
CAS原理剖析
CAS 被认为是一种乐观锁,有乐观锁,相对应的是悲观锁。
在上述示例中,我们使用了 synchronized,如果在线程竞争压力大的情况下,synchronized 内部会升级为重量级锁,此时仅能有一个线程进入代码块执行,如果这把锁始终不能释放,其他线程会一直阻塞等待下去。此时,可以认为是悲观锁。
悲观锁会因线程一直阻塞导致系统上下文切换,系统的性能开销大。
那么,我们可以用乐观锁来解决,所谓的乐观锁,其实就是一种思想。
乐观锁,会以一种更加乐观的态度对待事情,认为自己可以操作成功。当多个线程操作同一个共享资源时,仅能有一个线程同一时间获得锁成功,在乐观锁中,其他线程发现自己无法成功获得锁,并不会像悲观锁那样阻塞线程,而是直接返回,可以去选择再次重试获得锁,也可以直接退出。
CAS 正是乐观锁的核心算法实现。
在示例代码的方案中都提到了 AtomicInteger、LongAdder、Lock锁底层,此外,当然还包括 java.util.concurrent.atomic 并发包下的所有原子类都是基于 CAS 来实现的。
以 AtomicInteger 原子整型类为例,一起来分析下 CAS 底层实现机制。
atomicData.incrementAndGet()
源码如下所示:
// 提供自增易用的方法,返回增加1后的值
public final int incrementAndGet() {return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}// 额外提供的compareAndSet方法
public final boolean compareAndSet(int expect, int update) {return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}// Unsafe 类的提供的方法
public final int getAndAddInt (Object o,long offset, int delta){int v;do {v = getIntVolatile(o, offset);} while (!weakCompareAndSetInt(o, offset, v, v + delta));return v;
}
我们看到了 AtomicInteger 内部方法都是基于 Unsafe 类实现的,Unsafe 类是个更底层硬件CPU指令通讯的复制工具类。
1、参数
由这段代码看到:
unsafe.compareAndSwapInt(this, valueOffset, expect, update)
所谓的 CAS,其实是个简称,全称是 Compare And Swap,对比之后交换数据。
上面的方法,有几个重要的参数:
(1)this,Unsafe 对象本身,需要通过这个类来获取 value 的内存偏移地址。
(2)valueOffset,value 变量的内存偏移地址。
(3)expect,期望更新的值。
(4)update,要更新的最新值。
如果原子变量中的 value 值等于 expect,则使用 update 值更新该值并返回 true,否则返回 false。
再看如何获得 valueOffset的:
// Unsafe实例
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset;static {try {// 获得value在AtomicInteger中的偏移量valueOffset = unsafe.objectFieldOffset(AtomicInteger.class.getDeclaredField("value"));} catch (Exception ex) { throw new Error(ex); }
}
// 实际变量的值
private volatile int value;
这里看到了 value 实际的变量,是由 volatile 关键字修饰的,为了保证在多线程下的内存可见性。
为何能通过 Unsafe.getUnsafe() 方法能获得 Unsafe 类的实例?其实因为 AtomicInteger 类也在 **rt.jar **包下面的,所以 AtomicInteger 类就是通过 Bootstrap 根类加载器进行加载的。
源码如下所示:
@CallerSensitive
public static Unsafe getUnsafe() {Class var0 = Reflection.getCallerClass();// Bootstrap 类加载器是C++的,正常返回null,否则就抛异常。if (!VM.isSystemDomainLoader(var0.getClassLoader())) {throw new SecurityException("Unsafe");} else {return theUnsafe;}
}
解密CAS底层指令
其实,掌握以上内容,对于 CAS 机制的理解相对来说算是比较清楚了。
当然,如果感兴趣,也可以继续深入学习用到了哪些硬件 CPU 指令。
底层硬件通过将 CAS 里的多个操作在硬件层面语义实现上,通过一条处理器指令保证了原子性操作。这些指令如下所示:
(1)测试并设置(Tetst-and-Set)
(2)获取并增加(Fetch-and-Increment)
(3)交换(Swap)
(4)比较并交换(Compare-and-Swap)
(5)加载链接/条件存储(Load-Linked/Store-Conditional)
前面三条大部分处理器已经实现,后面的两条是现代处理器当中新增加的。而且根据不同的体系结构,指令存在着明显差异。
在IA64,x86 指令集中有 cmpxchg 指令完成 CAS 功能,在 sparc-TSO 也有 casa 指令实现,而在 ARM 和 PowerPC 架构下,则需要使用一对 ldrex/strex 指令来完成 LL/SC 的功能。在精简指令集的体系架构中,则通常是靠一对儿指令,如:load and reserve 和 **store conditional ** 实现的,在大多数处理器上 CAS 都是个非常轻量级的操作,这也是其优势所在。
sun.misc.Unsafe 中 CAS 的核心方法:
public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5);public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);
这三个方法可以对应去查看 openjdk 的 hotspot 源码:
#define FN_PTR(f) CAST_FROM_FN_PTR(void*, &f){CC"compareAndSwapObject", CC"("OBJ"J"OBJ""OBJ")Z", FN_PTR(Unsafe_CompareAndSwapObject)},{CC"compareAndSwapInt", CC"("OBJ"J""I""I"")Z", FN_PTR(Unsafe_CompareAndSwapInt)},{CC"compareAndSwapLong", CC"("OBJ"J""J""J"")Z", FN_PTR(Unsafe_CompareAndSwapLong)},
cmpxchg 函数源码:
jbyte Atomic::cmpxchg(jbyte exchange_value, volatile jbyte*dest, jbyte compare_value) {assert (sizeof(jbyte) == 1,"assumption.");uintptr_t dest_addr = (uintptr_t) dest;uintptr_t offset = dest_addr % sizeof(jint);volatile jint*dest_int = ( volatile jint*)(dest_addr - offset);// 对象当前值jint cur = *dest_int;// 当前值cur的地址jbyte * cur_as_bytes = (jbyte *) ( & cur);// new_val地址jint new_val = cur;jbyte * new_val_as_bytes = (jbyte *) ( & new_val);// new_val存exchange_value,后面修改则直接从new_val中取值new_val_as_bytes[offset] = exchange_value;// 比较当前值与期望值,如果相同则更新,不同则直接返回while (cur_as_bytes[offset] == compare_value) {// 调用汇编指令cmpxchg执行CAS操作,期望值为cur,更新值为new_valjint res = cmpxchg(new_val, dest_int, cur);if (res == cur) break;cur = res;new_val = cur;new_val_as_bytes[offset] = exchange_value;}// 返回当前值return cur_as_bytes[offset];
}
源码中具体变量添加了注释,因为都是 C++ 代码,所以作为了解即可 ~
jint res = cmpxchg(new_val, dest_int, cur);
相关文章:
一文搞懂CAS实现原理——怀玉
点个关注,必回关 文章目录CAS原理剖析1、参数解密CAS底层指令CAS(Compare and swap)是一种用于在多线程环境下实现同步功能的机制CAS原理剖析 CAS 被认为是一种乐观锁,有乐观锁,相对应的是悲观锁。 在上述示例中&…...
typora每次复制文档都要附带图片文件夹?学会配置gitee图床
0. 引言 作为开发人员,我们习惯使用md格式来编写文档,特别是typora编辑器更是日常使用的软件。但作为轻量化的文档编辑器,我们在默认插入图片时,一般typora会将图片保存到本地或者引用一个本地图片的路径 当文档还在我们本地打开…...
Linux--gdb
gdb用于实现在linux下通过gdb进行调试。由于gcc、g生成的文件是release文件,而不是用于调试的debug文件,所以需要使用gcc -g命令,生成debug文件 调试器:核心工作,主要是为了定位问题 所有查看内容的指令,不…...
c++11 标准模板(STL)(std::multimap)(二)
定义于头文件 <map> template< class Key, class T, class Compare std::less<Key>, class Allocator std::allocator<std::pair<const Key, T> > > class multimap;(1)namespace pmr { template <class Key, class T…...
【数据结构】二叉排序树——平衡二叉树的调整
文章目录前置概念一、构造平衡二叉树的基本思想二、一个示例三、平衡二叉树的调整细节(1)LL型(顺时针 )举例(2)RR型(逆时针)(3)LR型(先逆时针再顺…...
03- pandas 数据库可视化 (数据库)
pandas库的亮点: 一个快速、高效的DataFrame对象,用于数据操作和综合索引;用于在内存数据结构和不同格式之间读写数据的工具:CSV和文本文件、Microsoft Excel、SQL数据库和快速HDF 5格式;智能数据对齐和丢失数据的综合处理&#…...
第三方电容笔怎么样?开学适合买的电容笔
随着科学技术的进步,很多新型的电子产品和数码设备都出现了。比如手机,IPAD,蓝牙耳机,电容笔等等。实际上,如果你想要更好的使用ipad,那么你就需要一支电容笔。比如ipad,我们用ipad来做笔记&…...
Java学习-IO流-字节输出流
Java学习-IO流-IO流的体系和字节输出流基本用法 //IO流 → 字节流 → 字节输入流:InputStream // ↘ ↘ 字节输出流:OutputStream // ↘ 字符流 → 字符输入流:Reader // ↘ 字符输出流:WriterFileInputStream…...
linux性能分析 性能之巅学习笔记和内容摘录
本文只是在阅读《性能之巅》的过程中,对一些觉得有用的地方进行的总结和摘录,并附加一些方便理解的材料,完整内容还请阅读Gregg的大作 概念和方法 性能分析领域一词的全栈代表了整个操作系统的软硬件在内的所有事物 软件生命周期和性能规划…...
机器学习笔记之生成模型综述(三)生成模型的表示、推断、学习任务
机器学习笔记之生成模型综述——表示、推断、学习任务引言生成模型的表示任务从形状的角度观察生成模型的表示任务从概率分布的角度观察生成模型的表示任务生成模型的推断任务生成模型的学习任务引言 上一节介绍了从监督学习、无监督学习任务的角度介绍了经典模型。本节将从表…...
第八章 Flink集成Iceberg的DataStreamAPI、TableSQLAPI详解
1、概述 目前Flink支持使用DataStream API 和SQL API方式实时读取和写入Iceberg表,建议使用SQL API方式实时读取和写入Iceberg表。 Iceberg支持的Flink版本为1.11.x版本以上,以下为版本匹配关系: Flink版本Iceberg版本备注Flink1.11.XI…...
PyTorch学习笔记:nn.Sigmoid——Sigmoid激活函数
PyTorch学习笔记:nn.Sigmoid——Sigmoid激活函数 torch.nn.Sigmoid()功能:逐元素应用Sigmoid函数对数据进行激活,将元素归一化到区间(0,1)内 函数方程: Sigmoid(x)σ(x)11e−xSigmoid(x)\sigma(x)\frac1{1e^{-x}} Sigmoid(x)σ(…...
个人学习系列 - 解决拦截器操作请求参数后台无法获取
由于项目需要使用拦截器对请求参数进行操作,可是请求流只能操作一次,导致后面方法不能再获取流了。 新建SpringBoot项目 1. 新建拦截器WebConfig.java /*** date: 2023/2/6 11:21* author: zhouzhaodong* description:*/ Configuration public class W…...
【编程基础之Python】2、安装Python环境
【编程基础之Python】2、安装Python环境安装Python环境在Windows上安装Python验证Python运行环境在Linux上安装Python验证Python运行环境总结安装Python环境 所谓“工欲善其事,必先利其器”。在学习Python之前需要先搭建Python的运行环境。由于Python是跨平台的&am…...
Java开发 - 问君能有几多愁,Spring Boot瞅一瞅。
前言 首先在这里恭祝大家新年快乐,兔年大吉。本来是想在年前发布这篇博文的,奈何过年期间走街串巷,实在无心学术,所以不得不放在近日写下这篇Spring Boot的博文。在还没开始写之前,我已经预见到,这恐怕将是…...
Office Server Document Converter Lib SDK Crack
关于 Office Server 文档转换器 (OSDC) 无需 Microsoft Office 或 Adobe 软件即可快速准确地转换文档。antennahouse.com Office Server 文档转换器 (OSDC) 会将您在 Microsoft Office(Word、Excel、PowerPoint)中创建的重要文档转换为高质量的 PDF …...
Cubox是什么应用?如何将Cubox同步至Notion、语雀、在线文档中
Cubox是什么应用? Cubox 是一款跨平台的网络收藏工具,通过浏览器扩展、客户端、手机应用、微信转发等方式,将网页、文字、图片、语音、视频、文件等内容保存起来,再经过自动整理、标签、分类之后,就可以随时阅读、搜索…...
计算机网络-传输层
文章目录前言概述用户数据报协议 UDP(User Datagram Protocol)传输控制协议 TCP(Transmission Control Protocol)TCP 的流量控制拥塞控制方法TCP 的运输连接管理TCP 的有限状态机总结前言 本博客仅做学习笔记,如有侵权,联系后即刻更改 科普:…...
HTML-CSS-js教程
HTML 双标签<html> </html> 单标签<img> html5的DOCTYPE声明 <!DOCTYPE html>html的基本骨架 <!DOCTYPE html> <html> </html>head标签 用于定义文档的头部。文档的头部包含了各种属性和信息,包括文档的标题&#…...
【Nacos】Nacos配置中心客户端启动源码分析
SpringCloud项目启动过程中会解析bootstrop.properties、bootstrap.yaml配置文件,启动父容器,在子容器启动过程中会加入PropertySourceBootstrapConfiguration来读取配置中心的配置。 PropertySourceBootstrapConfiguration#initialize PropertySource…...
ChromePass终极指南:浏览器密码提取与安全管理完全攻略
ChromePass终极指南:浏览器密码提取与安全管理完全攻略 【免费下载链接】chromepass Get all passwords stored by Chrome on WINDOWS. 项目地址: https://gitcode.com/gh_mirrors/chr/chromepass 副标题:从密码危机到数据掌控:3步实现…...
WiFi热图绘制工具:用Python为你的无线网络做一次“CT扫描“ [特殊字符][特殊字符]
WiFi热图绘制工具:用Python为你的无线网络做一次"CT扫描" 🏥📶 【免费下载链接】wifi-heat-mapper whm also known as wifi-heat-mapper is a Python library for benchmarking Wi-Fi networks and gather useful metrics that can…...
制造业生产管理应用搭建指南:轻流无代码平台完整实施流程——生产效率提升 300% 方法论
制造业生产管理应用搭建指南:轻流无代码平台完整实施流程——生产效率提升 300% 方法论制造业生产管理应用搭建指南:轻流无代码平台完整实施流程——生产效率提升 300% 方法论引言:背景与重要性工信部《智能制造发展规划》明确提出࿰…...
客服服务时长难统计?RPA自动记时长,排班更合理
RPA在客服服务时长统计中的应用客服服务时长的准确统计是优化排班和提高效率的关键。传统手动统计方式存在误差大、效率低等问题。RPA(机器人流程自动化)技术可以自动记录客服工作时长,为排班提供数据支持。RPA自动记录客服工作时长的实现方式…...
2026 AI大模型岗位薪资全曝光:从30k到80w,程序员必备指南,非常详细收藏我这一篇就够了
文章主要展示了2026年AI领域热门岗位的薪资情况,包括华为、腾讯、联影等公司在多个城市的AI工程师、大模型算法等职位的薪资水平。数据显示AI人才市场需求旺盛,薪资从月薪3.6万到年包80万不等。文章提供了AI薪资专场的链接,邀请读者了解更多行…...
RustDesk 中继服务器搭建指南:告别卡顿,实现高效远程控制
1. 为什么你需要自建RustDesk中继服务器 远程办公已经成为现代工作方式的标配,但很多人在使用公共远程控制服务时都遇到过令人抓狂的卡顿问题。想象一下,你正在紧急处理服务器故障,画面却卡成了PPT;或者需要远程协助家人修电脑&a…...
你还在给每个图片父元素加类名?CSS :has() 让选择器“逆天改命”
你还在给每个图片父元素加类名?CSS :has() 让选择器“逆天改命” 引言 “组长,这个需求我写不了。” “什么需求?” “产品经理说,所有包含图片的卡片,要在卡片上加一个‘带图标识’的边框。但是这些卡片是动态渲染的&…...
OpenClaw+Qwen3-32B科研助手:文献综述自动生成与参考文献整理
OpenClawQwen3-32B科研助手:文献综述自动生成与参考文献整理 1. 为什么需要AI科研助手? 作为一名计算机专业的研究生,我每天要处理大量文献。最痛苦的时刻莫过于导师突然说"下周组会做个文献综述",而我手头只有几十篇…...
微信支付回调通知收不到的5个隐藏坑(附.NET Core实战解决方案)
微信支付回调通知失效的深度排查与.NET Core实战指南 当支付流程顺利完成但回调通知却神秘消失时,这种"薛定谔式的支付成功"往往让开发者陷入调试泥潭。本文将揭示五个容易被忽视的技术暗礁,并提供可直接集成到生产环境的.NET Core解决方案。 …...
大厂速报:小红书期权涨麻,字节年终暴击,AI赛道卷疯了
互联网圈没有岁月静好,只有暗潮涌动——大厂裁员传闻从未断档,AI内卷卷到凌晨三点,打工人一边焦虑KPI,一边蹲守大厂福利,有人靠期权实现财富跃迁,有人被组织调整撞个正着。一、核心福利|打工人狂…...
