CAS的超~详细介绍
什么是CAS
CAS全称Compare and swap,是一种比较特殊的CPU指令. 字面意思:"比较并交换",
一个CAS涉及到以下操作:
我们假设内存中的原数据为V,旧的预期值A,需要修改的新值B.
1.比较A和V是否相等(比较)
2.如果相等,将B写入V.(交换)
3.返回操作是否成功.
伪代码
下面写的代码不是原子的,真实的CAS是一个原子的硬件指令完成的.这个伪代码只是辅助理解CAS的工作流程.
boolean CAS(address, expectValue, swapValue) {if(&address == expectedValue) {&address = swapValue;return true;}return false;
}
其中,address表示内存地址,expectValue和swapValue表示寄存器中的值.
流程就是比较address内存地址中的值是否与expect寄存器中的值相同.如果相同,就把swap寄存器中的值和address中的值进行交换(说是交换,实际上是赋值,其实完了之后我们往往只关注内存中的值,寄存器中的值,就不需要了),返回true. 如果不同,无事发生,返回false.
CAS是怎么实现的
针对不同的操作系统,JVM用到了不同的CAS实现原理(操作系统对指令进行封装,JVM又对操作系统提供的api又封装了一层.),简单来讲:
java的CAS利用的是unsafe这个类提供的CAS操作;(这样的操作,涉及到一些系统底层内容,使用不当,可能会带来风险,一般不建议直接用CAS)
unsafe的CAS依赖了的是jvm针对不同的操作系统实现的Atomic::cmpxchg
Atomic::cmpxchg的实现使用了汇编的CAS操作,并使用cpu硬件提供的lock机制保证其原子性.
简而言之,是因为硬件予以支持,软件层面才能做到.
CAS有哪些应用
实现原子类
标准库中提供了java.util.concurrent.atomic包,里面的类都是基于这种方式来实现的.典型的就是AtomicInteger类.其中getAndIncrement相当于i++操作.
AtomicInteger atomicInteger = new AtomicInteger(0);
//相当于i++操作(但实际上只是一个指令,它天然是原子的)
atomicInteger.getAndIncrement();
伪代码实现:
class AtomicInteger {private int value;public int getAndIncrement() {int oldValue = value;//发现value与oldValue不同.意味着CAS之前另一个线程修改了value//通过该方式,能意识到被修改while ( CAS(value, oldValue, oldValue + 1) != true) {oldValue = value;}//发现value被修改过,就重新读取新的value到OldValue中return oldValue;}
}
假设两个线程同时调用getAndIncrement
1.两个线程都读取value的值到oldValue中.(oldValue是一个局部变量,在栈上.每个线程都有自己的栈)

2.线程1先执行CAS操作,由于oldValue和value的值相同,直接对value进行赋值.
注意:
CAS是直接读内存的,而不是操作寄存器.
CAS的读内存,比较,写内存是一条硬件指令,是原子的.

3.线程2再执行CAS操作,第一次CAS的时候发现oldValue和value不相等,不能进行赋值.因此需要进入循环.
在循环里重新读取value的值赋给oldValue
4.线程2接下来第二次执行CAS,此时oldValue和value相同,于是直接执行赋值操作.
5.线程1和线程2返回各自的oldValue的值即可.
通过形如上述代码就可以实现一个原子类.不需要使用重量级锁,就可以高效的完成多线程的自增操作.
实现自旋锁
基于CAS实现更灵活的锁,获取到更多的控制权.
public class SpinLock {private Thread owner = null;public void lock() {//通过CAS看当前锁是否被某个线程持有.//如果这个锁已经被别的线程持有,那么就自旋等待.//如果这个锁没有被别的线程持有,那么就把owner设为当前尝试加锁的线程while(!CAS(this.owner, null, Thread.currentThread())) {//当owner不为null的时候,循环就会一直执行下去,通过这样的"忙等"来完成等待效果}//阻塞式的等.让线程不参与cpu调度了,此处自旋式的等,没有放弃cpu//不会参与到调度,也就没有了调度开锁了.但缺点就是消耗了更多的cpu public void unlock() {this.owner = null;}}
}
CAS的ABA问题
什么是ABA问题
ABA的问题:
假设存在两个线程t1,t2.有一个共享变量num,初始值为A.
接下来,线程t1想使用CAS把num变成Z,那么就需要
先读取num的值,记录到oldNum变量中
使用CAS判定当前num的值是否为A,如果为A,就要修改成Z.
但是,在t1执行这两个操作之间,t2线程可能把num的值从A改成了B,又从B改成了A.
线程t1的CAS期望num不变就修改.但是num的值已经被t2给改了.只不过又改成A了.这个时候t1究竟是否要更改num的值为Z呢?
到这一步,t1线程无法区别当前这个变量始终是A,还是经历了一个变化过程.

这就好比,我们买一个手机,无法判定这个手机是刚出厂的新手机,还是别人用旧了,又翻新过的手机.
ABA问题引来的BUG
大部分情况下,t2线程这样的一个反复横跳改动,对于t1是否修改num是没有影响的.但是不排除一些特殊情况.
假设一个人有1000元存款,他想从中取出500块钱.
取钱的时候ATM卡了,按了一下没反应(t1),又按了一下(t2)还是没反应
按理来说这应该是正常的.
1.存款1000,线程1获取到当前存款值1000,期望更新为500;线程2获取到当前存款值1000,期望更新为500.
2.线程1执行成功.存款被改为500,线程2阻塞等待中.
3.轮到线程2执行了,发现当前存款为500,与之前读到的1000不同,执行失败.
但如果出现了极端情况:比如中间有人给你转了500.
这个时候线程2发现当前存款为1000,与1000相同,又扣款了一次.
这个时候,就被扣款了两次,这都是ABA问题搞的鬼!!
解决方案
1.约定数据的变化是单向的(只能增加或者只能减少),不是双向的(既能增加又能减少)
2.给要修改的值,引入版本号.在CAS比较当前值与旧值的同时,也要比较版本号是否符合预期.
(1)CAS操作在读取旧值的同时,也要读取版本号
(2)真正修改的时候,
如果当前版本号和读到的版本号相同,就修改数据,并把版本号+1
如果当前版本号高读到的版本号.就操作失败(认为数据已经被修改过了)
相关面试题
1.讲解下你自己了解的CAS机制
全程Compare and swap, 即"比较并交换".相当于通过一个原子的操作,同时完成"读取内存,比较是否相等,修改内存"这三个步骤.本质上需要CPU指令的支撑
2.ABA问题怎么解决
给要修改的数据引入版本号.在CAS比较当前值和旧值的同时,也要比较版本号是否符合预期.如果返现当前版本号和之前读到的版本号一致,就真正执行修改操作,并让版本号自增;如果发现当前版本号比之前大,则视为操作失败
相关文章:
CAS的超~详细介绍
什么是CAS CAS全称Compare and swap,是一种比较特殊的CPU指令. 字面意思:"比较并交换", 一个CAS涉及到以下操作: 我们假设内存中的原数据为V,旧的预期值A,需要修改的新值B. 1.比较A和V是否相等(比较) 2.如果相等,将B写入V.(交换) 3.返回操作是否成功. 伪代码 下面…...
Scott用户数据表的分析
Oracle从入门到总裁:https://blog.csdn.net/weixin_67859959/article/details/135209645 如果想要知道某个用户所有的数据表: select * from tab; 此时结果中一共返回了四张数据表,分别为部门表(dept) ,员工表(emp&a…...
网络基础学习(3):交换机
1.交换机结构 (1)网线接口和后面的电路部分加在一起称为一个端口,也就是说交换机的一个端口就相当于计算机上的一块网卡。 如果在计算机上安装多个网卡,并让网卡接收所有网络包,再安装具备交换机功能的软件࿰…...
【软件测试学习笔记2】用例设计方法
1.能对穷举场景设计测试点(等价法) 等价类: 说明:在所有测试数据中,具有某种共同特征的数据集合进行划分 分类:有效等价类:满足需求的数据集合 无效等价类:不满足需求的数据集合 步…...
蓝桥杯 第三场 小白入门赛
召唤神坤 有意思🤔(ikun)。虽然是第一题但也要配得上神坤的身份。 思路1 枚举分母,选择一个数据结构来选出分母两侧最大的两个数做分子。2s常数大些也无碍。我选择好写的ST表 思路2 写两个 d p dp dp 分别表示 1 1 1 到 i…...
网络安全等级保护测评规划与设计
笔者单位网络结构日益复杂,应用不断增多,使信息系统面临更多的风险。同时,网络攻防技术发展迅速,攻击的技术门槛随着自动化攻击工具的应用也在不断降低,勒索病毒等未知威胁也开始泛滥。基于此,笔者单位拟进…...
Error: Cannot find module ‘vue-template-compiler‘ 问题解决
启动Vuepress项目时报了如下错误:Error: Cannot find module vue-template-compiler Error: Cannot find module vue-template-compiler Require stack: - /usr/local/lib/node_modules/vuepress/node_modules/vue-loader/lib/compiler.js - /usr/local/lib/node_…...
华为认证云计算专家(HCIE-Cloud Computing)--练习题
华为认证云计算专家(HCIE-Cloud Computing)–练习题 1.(判断题)华为云stack支持鲲鹏架构,业务可从X86过渡到鲲鹏。 正确答案:正确 2.(判断题)业务上云以后,安全方面由云服务商负责,客户自己不需要做任何防…...
【MATLAB】【数字信号处理】产生系统的单位冲激响应h(t)与H(z)零极点分布
一、实验目的与要求 产生h(t) 与H(z) 零极点分布 二、实验仪器 微机,仿真软件MATLAB 2022a 三、实验内容与测试结果 1.已知描述连续系统的微分方程为y(t)5y(t)6y(t)2x(t)8x(t) ,计算系统的单位冲激响应h(t) 程序如下: clear all; ts0;…...
实验五:动态路由配置
实验五:动态路由配置 1.RIP 配置 【实验名称】 RIP 路由协议配置 【实验目的】掌握路由器 RIP 路由协议的基本配置 【实验设备】路由器( 2 台)、计算机( 2 台)、配置电缆( 1 根)、 V…...
苍穹外卖学习----出错记录
1.微信开发者工具遇到的问题: 1.1appid消失报错: {errMsg: login:fail 系统错误,错误码:41002,appid missing [20240112 16:44:02][undefined]} 1.2解决方式: appid可在微信开发者官网 登录账号后在开发栏 找到 复制后按以下步骤粘贴即…...
如何实现图片压缩
文章目录 1、canvas实现图片压缩2、其他 1、canvas实现图片压缩 canvas 实现图片压缩,主要是使用 canvas 的drawImage 方法 具体思路 拿到用户上传的文件转成base64创建一个 Image,主要是获取到这个图片的宽度和高度创建一个 2D 的画布,画布…...
机器学习算法实战案例:时间序列数据最全的预处理方法总结
文章目录 1 缺失值处理1.1 统计缺失值1.2 删除缺失值1.3 指定值填充1.4 均值/中位数/众数填充1.5 前后项填充 2 异常值处理2.1 3σ原则分析2.2 箱型图分析 3 重复值处理3.1 重复值计数3.2 drop_duplicates重复值处理 3 数据归一化/标准化3.1 0-1标准化3.2 Z-score标准化 技术交…...
MongoDB高级集群架构设计
两地三中心集群架构设计 容灾级别 RPO & RTO RPO(Recovery Point Objective):即数据恢复点目标,主要指的是业务系统所能容忍的数据丢失量。RTO(Recovery Time Objective):即恢复时间目标&…...
C++中JSON与string格式互转
1、JSON-》string 操作步骤: 1、在C中新建一个json对象并赋值,然后将其转给char *data。 2、在使用 #include <json.h> 头文件时,通常是使用第三方库 jsoncpp。由于它不是标准库的一部分,所以需要从官网http://jsoncpp.sou…...
2023一带一路暨金砖国家技能发展与技术创新大赛 【企业信息系统安全赛项】国内赛竞赛样题
2023一带一路暨金砖国家技能发展与技术创新大赛 【企业信息系统安全赛项】国内赛竞赛样题 2023一带一路暨金砖国家技能发展与技术创新大赛 【企业信息系统安全赛项】国内赛竞赛样题第一阶段: CTF 夺旗项目1. CTF 夺旗任务一 命令注入任务二 SQL 注入 项目2. 序列化漏…...
【BBuf的CUDA笔记】十二,LayerNorm/RMSNorm的重计算实现
带注释版本的实现被写到了这里:https://github.com/BBuf/how-to-optim-algorithm-in-cuda/tree/master/apex 由于有很多个人理解,读者可配合当前文章谨慎理解。 0x0. 背景 我也是偶然在知乎的一个问题下看到这个问题,大概就是说在使用apex的…...
安装Mac提示安装无法继续,因为安装器已损坏
目录 事件起因报错原因 事件起因 有两台电脑,由于电脑1下载镜像文件很快,于是我先用电脑1下载这个大文件,然后安装openresty,电脑2用http链接下载这个大文件。电脑2安装中途就报安装无法继续,因为安装器已损坏。 报错原因 不知…...
脚本编程游戏引擎会遇到哪些问题
在游戏开发中,脚本编程已经成为了一种非常常见的方式,用来实现游戏逻辑和功能。但是脚本编程游戏引擎也可能会面临一些挑战和问题。下面简单的探讨一下都会遇到哪些问题,并且该如果做。 性能问题 脚本语言通常需要运行时解释执行࿰…...
什么软件可以做报表?
数据报表,是商业领域中不可或缺的一部分,它通过表格、图表等形式,将复杂的数据进行整理、分析并呈现出来,帮助用户更好地理解数据的趋势和关系。数据报表不仅展示了业务现状和趋势,还支持多种数据分析和挖掘功能&#…...
Linux链表操作全解析
Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表?1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...
关于nvm与node.js
1 安装nvm 安装过程中手动修改 nvm的安装路径, 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解,但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后,通常在该文件中会出现以下配置&…...
django filter 统计数量 按属性去重
在Django中,如果你想要根据某个属性对查询集进行去重并统计数量,你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求: 方法1:使用annotate()和Count 假设你有一个模型Item,并且你想…...
【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例
文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...
在四层代理中还原真实客户端ngx_stream_realip_module
一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡(如 HAProxy、AWS NLB、阿里 SLB)发起上游连接时,将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后,ngx_stream_realip_module 从中提取原始信息…...
让AI看见世界:MCP协议与服务器的工作原理
让AI看见世界:MCP协议与服务器的工作原理 MCP(Model Context Protocol)是一种创新的通信协议,旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天,MCP正成为连接AI与现实世界的重要桥梁。…...
多种风格导航菜单 HTML 实现(附源码)
下面我将为您展示 6 种不同风格的导航菜单实现,每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...
dify打造数据可视化图表
一、概述 在日常工作和学习中,我们经常需要和数据打交道。无论是分析报告、项目展示,还是简单的数据洞察,一个清晰直观的图表,往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server,由蚂蚁集团 AntV 团队…...
ABAP设计模式之---“简单设计原则(Simple Design)”
“Simple Design”(简单设计)是软件开发中的一个重要理念,倡导以最简单的方式实现软件功能,以确保代码清晰易懂、易维护,并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计,遵循“让事情保…...
安全突围:重塑内生安全体系:齐向东在2025年BCS大会的演讲
文章目录 前言第一部分:体系力量是突围之钥第一重困境是体系思想落地不畅。第二重困境是大小体系融合瓶颈。第三重困境是“小体系”运营梗阻。 第二部分:体系矛盾是突围之障一是数据孤岛的障碍。二是投入不足的障碍。三是新旧兼容难的障碍。 第三部分&am…...
