【JavaEE初阶系列】——CAS
目录
🎈什么是 CAS
📝CAS 伪代码
🎈CAS 是怎么实现的
🎈CAS 有哪些应用
🚩实现原子类
🌈伪代码实现:
🚩实现自旋锁
🌈自旋锁伪代码
🎈CAS 的 ABA 问题
🚩什么是 ABA 问题
🚩ABA 问题引来的 BUG
🎈CAS相关面试题
🎈什么是 CAS
我们假设内存中的原数据V,旧的预期值A,需要修改的新值B。
- 1. 比较 A 与 V 是否相等。(比较)
- 2. 如果比较相等,将 B 写入 V。(交换)
- 3. 返回操作是否成功。
CAS 比较交换的是 内存 和 寄存器。比如有一个内存M,现在有俩个寄存器A,B.
CAS(M,A,B)如果M和A的值相同的话,就把M和B的值交换,同时整个操作返回true.
如果M和A的值不同的话,无事发生,同时整个操作返回false.
📝CAS 伪代码
伪代码 ,代码是不能真正编译执行(不符合语法要求) 认识到逻辑是啥样的。
boolean CAS(address, expectValue, swapValue) {
if (&address == expectedValue) {&address = swapValue;return true;}return false;
} 两种典型的不是 "原子性" 的代码
- 1. check and set (if 判定然后设定值) [上面的 CAS 伪代码就是这种形式]
- 2. read and update (i++) [之前我们讲线程安全的代码例子是这种形式]
当多个线程同时对某个资源进行 CAS 操作,只能有一个线程操作成功,但是并不会阻塞其他线程 , 其他线程只会收到操作失败的信号。CAS 可以视为是一种乐观锁. (或者可以理解成 CAS 是乐观锁的一种实现方式)
CAS其实是一个cpu指令(一个cpu指令,就能完成上述比较交换的逻辑)单个cpu指令,是原子的!就可以使用CAS完成一些操作,进一步的替代"加锁"。——这样就给编写线程安全的代码,引入了新的思路。
基于CAS实现线程安全的方式,也称为"无锁编程",
- 优点:保证线程安全,同时避免阻塞(效率)
- 缺点:代码会更复杂,不好理解,只能够适合一些特定的场景,不如加锁方式更普实。
🎈CAS 是怎么实现的
CAS本质上是cpu提供的指令——》又被操作系统封装,提供成api,然后又被JVM,也提供成api——》程序员就可以使用了。
针对不同的操作系统, JVM 用到了不同的 CAS 实现原理,简单来讲:
- java 的 CAS 利用的的是 unsafe 这个类提供的 CAS 操作;
- unsafe 的 CAS 依赖了的是 jvm 针对不同的操作系统实现的 Atomic::cmpxchg;
- Atomic::cmpxchg 的实现使用了汇编的 CAS 操作,并使用 cpu 硬件提供的 lock 机制保证其原子性。
简而言之,是因为 硬件予以了支持,软件层面才能做到。
等到后面会更加能理解。
🎈CAS 有哪些应用
🚩实现原子类
int 进行++,不是原子的(load,add,save)三步骤。
AtomicInteger,基于CAS的方式对int进行封装,此时进行++,就是原子的了。(++操作是基于CAS指令实现的)
标准库中提供了 java.util.concurrent.atomic 包, 里面的类都是基于这种方式来实现的.典型的就是 AtomicInteger 类. 其中的 getAndIncrement 相当于 i++ 操作.
在java中,有些操作是偏底层的操作,偏底层的操作在使用的时候有更多的注意事项,稍有不慎就容易写出问题。这些操作,就会放到unsafe中进行归类。unsafe代表有更多的注意事项,稍有不慎就写错。(就比如在导航的时候,遇到事故多发地方就会提醒警告信息)
我们看到原子类内部没有使用synchronized加锁使用。
native是本地方法,compareAndSwapInt比较和交换,JVM源码中,使用c++实现逻辑,底层的操作。
- 原子类里面基于CAS实现的。 通过利用指令原子性逻辑获取锁实现原子性操作。
🌈伪代码实现:
class AtomicInteger {private int value;public int getAndIncrement() {int oldValue = value;while ( CAS(value, oldValue, oldValue+1) != true) {oldValue = value;}return oldValue;}
} 
初始情况下,value的值是0,俩次自增结果是2.


如果俩者相等,就返回true,并且让oldValue+1赋值给value,让value+1,如果不相等就得让value赋值给oldvalue,然后进行++操作。
所以我们之前所说的”线程不安全“本质上是进行自增的过程中,穿插执行了。
CAS也是让这里的自增,不要穿插执行,核心思路和加锁是类似的,加锁是通过阻塞的方式,避免穿插,CAS则是会通过重试的方式,避免穿插。

🚩实现自旋锁
🌈自旋锁伪代码
public class SpinLock {private Thread owner = null;public void lock(){// 通过 CAS 看当前锁是否被某个线程持有. // 如果这个锁已经被别的线程持有, 那么就自旋等待. // 如果这个锁没有被别的线程持有, 那么就把 owner 设为当前尝试加锁的线程. while(!CAS(this.owner, null, Thread.currentThread())){}}public void unlock (){this.owner = null;}
} 记录当前这个锁被哪个线程获取到了,如果是null,表示未加锁状态。
🎈CAS 的 ABA 问题
🚩什么是 ABA 问题
ABA 的关键问题 : 是通过值"没有发生改变"来作为”没有其他线程穿插执行“判定依据。但是这种判定方式不够严谨,更极端的情况下,可能有另一个线程穿插进来,把值从A->B->A,针对第一个线程来说,看起来好像是这个值,没变,实际上已经被穿插执行了。
比如,买个手机,买到的是一个”二手的,翻新的设备“。翻新机,也不是不能用,里面可能会有一些暗伤。ABA问题如果真的出现了,其实大部分情况下是不会产生bug的,就相当于买到二手设备,也是能用的,虽然另一个线程穿插执行了,由于值又改回来了,此时逻辑上也不一定会产生bug。
🚩ABA 问题引来的 BUG
假设这个场景,我去ATM取钱,我本身的账户1000,我想要取500,我再取钱的过程中,出现bug了,我按下取钱按钮的时候,没反应,又按了一下,此时就产生了俩个线程进行扣款操作。

由于t3线程正好又在这个节骨眼上转来了500,与时我的余额又是1000了,就会导致t1线程也能扣款。此时我预期取500,实际上扣了1000.
大部分情况下ABA问题其实没啥大事,但是有一些极端情况,会使ABA出现bug,只要让判定的数值,按照一个方向增长即可。有增有减,就可能出现ABA,只是增加,或者只是减少,针对像账户余额这样概念,本身就应该要能增有减,可以引入一个额外的变量,版本号,约定每次修改余额就让版本号自增,此时在使用CAS判定的时候,就不是直接判定余额了,而是判定版本号,看版本号是否是变化了,如果版本号不变,注定没有线程穿插了执行。
🎈相关面试题
1) 讲解下你自己理解的 CAS 机制compareAndSwap 比较并且交换,相当于一个原子操作,同时完成 , "读取内存, 比较是否相等, 修改内存" 这三个步骤. 本质上需要 CPU 指令的支撑。通过利用指令的原子性从而避免获取锁实现了原子性操作。2) ABA问题怎么解决?给要修改的变量添加一个版本号,在 CAS 比较数据当前值和旧值的同时, 也要比较版本号是否符合预期.如果发现当前版本号和之前读到的版本号一致, 就真正执行修改操作, 并让版本号自增; 如果发现当前版本号比之前读到的版本号大, 就认为操作失败
难道父母眼里只有学习学习嘛??
相关文章:
【JavaEE初阶系列】——CAS
目录 🎈什么是 CAS 📝CAS 伪代码 🎈CAS 是怎么实现的 🎈CAS 有哪些应用 🚩实现原子类 🌈伪代码实现: 🚩实现自旋锁 🌈自旋锁伪代码 🎈CAS 的 ABA 问题 &#…...
webGIS 之 智慧校园案例
1.引入资源创建地图 //index.html <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content&qu…...
CVAE——生成0-9数字图像(Pytorch+mnist)
1、简介 CVAE(Conditional Variational Autoencoder,条件变分自编码器)是一种变分自编码器(VAE)的变体,用于生成有条件的数据。在传统的变分自编码器中,生成的数据是完全由潜在变量决定的&…...
【Linux】TCP网络套接字编程+守护进程
文章目录 日志类(完成TCP/UDP套接字常见连接过程中的日志打印)单进程版本的服务器客户端通信多进程版本和多线程版本守护进程化的多线程服务器 日志类(完成TCP/UDP套接字常见连接过程中的日志打印) 为了让我们的代码更规范化&…...
【Qt 学习笔记】Day2 | 认识QtSDK中的重要工具
博客主页:Duck Bro 博客主页系列专栏:Qt 专栏关注博主,后期持续更新系列文章如果有错误感谢请大家批评指出,及时修改感谢大家点赞👍收藏⭐评论✍ Day2 | 认识QtSDK中的重要工具 文章编号:Qt 学习笔记 / 03…...
adc123456
DMA主要用于协助CPU完成数据转运的工作 DMA,英文全称Direct Memory Access,DMA这个外设是可以直接访问STM32内部存储器的,包括运行内存SRAM,程序存储器flash和寄存器等等,DMA都有权限访问,所以DMA能完成数据…...
YOLOV5训练自己的数据集教程(万字整理,实现0-1)
文章目录 一、YOLOV5下载地址 二、版本及配置说明 三、初步测试 四、制作自己的数据集及转txt格式 1、数据集要求 2、下载labelme 3、安装依赖库 4、labelme操作 五、.json转txt、.xml转txt 六、修改配置文件 1、coco128.yaml->ddjc_parameter.yaml 2、yolov5x.…...
精通Go语言文件上传:深入探讨r.FormFile函数的应用与优化
1. 介绍 1.1 概述 在 Web 开发中,文件上传是一项常见的功能需求,用于允许用户向服务器提交文件,如图像、文档、视频等。Go 语言作为一门强大的服务器端编程语言,提供了方便且高效的方式来处理文件上传操作。其中,r.F…...
【C语言】字符串
C语言用字符数组存放字符串,字符数组中的各元素依次存放字符串的各字符 一维字符数组:存放一个字符串(每个数组元素存放一个字符)二维字符数组:存放多个一维数组(字符串);二维数组的…...
云计算探索-DAS、NAS与SAN存储技术演进及其应用比较
1,介绍 随着信息技术的飞速发展,数据存储的需求日益增长,各种存储技术也应运而生。在众多的存储解决方案中,直接附加存储(Direct Attached Storage,简称DAS)、网络附加存储(Network …...
手机有线投屏到直播姬pc端教程
1 打开哔哩哔哩直播姬客户端并登录(按下图进行操作) 2 手机用usb数据线连接电脑(若跳出安装驱动的弹窗点击确定或允许),usb的连接方式为仅充电(手机差异要求为仅充电),不同品牌手机要求可能不一样,根据实际的来 3 在投屏过程中不要更改usb的连接方式(不然电脑会死机需要重启) …...
SOA、分布式、微服务之间的关系?
分布式它本身就是一种系统部署的架构理念,意思就是将一个系统拆分为各个部分,然后分别部署到不同的机器上去,SOA和微服务项目的部署方式都可以是分布式架构。 而SOA和微服务它们都是面向服务的架构,但是微服务相比于SOA在服务粒度…...
Java多线程学习(概念笔记)
面试题:并行和并发有什么区别? 现在都是多核CPU,在多核CPU下 并发是同一时间应对多件事情的能力,多个线程轮流使用一个或多个CPU 并行是同一时间动手做多件事情的能力,4核CPU同时执行4个线程 面试题:创建线…...
【C++】set和map
set和map就是我们上篇博客说的key模型和keyvalue模型。它们属于是关联式容器,我们之前说过普通容器和容器适配器,这里的关联式容器就是元素之间是有关联的,通过上篇博客的讲解我们也对它们直接的关系有了一定的了解,那么下面我们先…...
yolov5 v7.0打包exe文件,使用C++调用
cd到yolo5文件夹下 pyinstaller -p 当前路径 -i logo图标 detect.py问题汇总 运行detect.exe找不到default.yaml 这个是yolov8里的文件 1 复制权重文件到exe所在目录。 2 根据报错提示的配置文件路径,把default.yaml复制放到相应的路径下。(缺少相应…...
保研线性代数机器学习基础复习2
1.什么是群(Group)? 对于一个集合 G 以及集合上的操作 ,如果G G-> G,那么称(G,)为一个群,并且满足如下性质: 封闭性:结合性:中性…...
vultr ubuntu 服务器远程桌面安装及连接
一. 概述 vultr 上开启一个linux服务器,都是以终端形式给出的,默认不带 ui 桌面的,那其实对于想使用服务器上浏览器时的情形不是很好。那有没有方法在远程服务器安装桌面,然后原程使用呢?至少ubuntu的服务器是有的&am…...
前端学习<二>CSS基础——12-CSS3属性详解:动画详解
前言 本文主要内容: 过渡:transition 2D 转换 transform 3D 转换 transform 动画:animation 过渡:transition transition的中文含义是过渡。过渡是CSS3中具有颠覆性的一个特征,可以实现元素不同状态间的平滑过渡…...
Sqoop 的安装与配置
目录 1 下载并解压2 修改配置文件3 添加环境变量4 拷贝 JDBC 驱动5 测试Sqoop是否能够成功连接数据库 下载地址 1 下载并解压 (1)上传安装包 sqoop-1.4.6.bin__hadoop-2.0.4-alpha.tar.gz 到 hadoop101 的 /opt/software 路径中 (2…...
Mysql设置访问权限(docker配置)
1.运行命令:docker exec -it 数据库名 bash,我这里是bot_test, docker exec -it bot_test bash 2.运行命令mysql -uroot -p --default-character-setutf8,输入密码连接数据库 3.运行命令show databases,查看当前的表 4.进入my…...
Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...
(二)TensorRT-LLM | 模型导出(v0.20.0rc3)
0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述,后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作,其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...
从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)
设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...
保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek
文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama(有网络的电脑)2.2.3 安装Ollama(无网络的电脑)2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...
全面解析数据库:从基础概念到前沿应用
在数字化时代,数据已成为企业和社会发展的核心资产,而数据库作为存储、管理和处理数据的关键工具,在各个领域发挥着举足轻重的作用。从电商平台的商品信息管理,到社交网络的用户数据存储,再到金融行业的交易记录处理&a…...
如何在Windows本机安装Python并确保与Python.NET兼容
✅作者简介:2022年博客新星 第八。热爱国学的Java后端开发者,修心和技术同步精进。 🍎个人主页:Java Fans的博客 🍊个人信条:不迁怒,不贰过。小知识,大智慧。 💞当前专栏…...
土建施工员考试:建筑施工技术重点知识有哪些?
《管理实务》是土建施工员考试中侧重实操应用与管理能力的科目,核心考查施工组织、质量安全、进度成本等现场管理要点。以下是结合考试大纲与高频考点整理的重点内容,附学习方向和应试技巧: 一、施工组织与进度管理 核心目标: 规…...
针对药品仓库的效期管理问题,如何利用WMS系统“破局”
案例: 某医药分销企业,主要经营各类药品的批发与零售。由于药品的特殊性,效期管理至关重要,但该企业一直面临效期问题的困扰。在未使用WMS系统之前,其药品入库、存储、出库等环节的效期管理主要依赖人工记录与检查。库…...
MLP实战二:MLP 实现图像数字多分类
任务 实战(二):MLP 实现图像多分类 基于 mnist 数据集,建立 mlp 模型,实现 0-9 数字的十分类 task: 1、实现 mnist 数据载入,可视化图形数字; 2、完成数据预处理:图像数据维度转换与…...
day51 python CBAM注意力
目录 一、CBAM 模块简介 二、CBAM 模块的实现 (一)通道注意力模块 (二)空间注意力模块 (三)CBAM 模块的组合 三、CBAM 模块的特性 四、CBAM 模块在 CNN 中的应用 一、CBAM 模块简介 在之前的探索中…...
