CAS问题

CAS

compare and swap

一个特殊的 CPU 指令 完成的工作,就是 "比较和交换"

这个 cpu 指令本身就是"原子的";

所以基于 cas 指令:给编写线程安全的代码打开了新的大门;

之前线程安全都是靠 加锁 ;导致的结果就是 阻塞===> 性能降低;

使用 CAS ,不仅不涉及加锁,也不会阻塞,合理使用也能保证线程安全(无锁编程)

CAS 本身是 CPU 指令;

操作系统 对 指令 进行了 封装;

jvm 又对 操作系统提供的 api 又封装了一层;

java 中 cas 的 api 放到了 unsafe包(不安全的)里(涉及到一些底层内容,使用不当会带来风险);

java标准库,对于 CAS 又进行了进一步的封装,提供了一些工具类;最主要的一个工具类,叫做 "原子类"

上述代码就处于 "线程不安全"的情况;

解决这个问题的第一个方法就是 给 写操作 加锁;

第二个方法就是 使用原子类;

这里的内容,就没有加锁,也能保证线程安全;

之前的 count++ 是cpu的 三个指令;

多个线程的写操作是三个指令,会相互穿插执行,引起线程不安全;

此处的 getAndIncrement 对变量的修改,是一个 CAS 指令;

一个指令就是原子的;加锁就是为了将三个指令 变成 一个指令 让它成为原子的;

不使用 原子类 的 写操作;

使用了 原子类 的写操作

CAS 中的 ABA 问题

CAS 在使用的时候 关键要点是要 判定当前内存是否和寄存器中的值一样,如果一样就进行修改,不一样就什么都不做

假设有两个线程 A 和 B 同时对同一个共享变量执行 CAS 操作:

线程 A 执行 CAS 操作:

线程 A 从内存读取当前值A,并设定预期值E为A(假设A的值为 10)。

线程 A 计算出新值N(比如N = E + 1,即 11)。

线程 A 执行 CAS 操作,比较内存处的值(也就是A)是否等于预期值E。如果相等,就将内存的值修改为新值N(即把 10 改成 11),操作成功。

线程 B 执行 CAS 操作:

线程 B 同样从内存地址V读取当前值,假设线程 B 读取时,线程 A 还未完成 CAS 操作,所以线程 B 读取到的值也是 10,它也设定预期值E为 10,并计算出新值N(同样为 11)。

当线程 B 执行 CAS 操作时,如果此时线程 A 已经完成了 CAS 操作,那么内存地址V处的值已经变为 11,而线程 B 的预期值E还是 10,两者不相等,线程 B 的 CAS 操作失败,不会修改内存地址V的值。

线程 B 失败后,根据具体的业务逻辑,可以选择重试,即重新读取内存值作为预期值,重新计算新值,再次执行 CAS 操作;也可以选择放弃本次操作,执行其他逻辑。

ABA 问题

存在一种情况:内存 V 存储的数值是 0;

执行CAS 之前,另一个线程把这个值从 0 --> 10 又从 10--> 0;

在其他前程穿插的过程中,将 内存v的值 从 A 改到 B 又改回 A;

此时 CAS 并不知道 修改了值,这种情况就是 : ABA 问题

一般来说是不会出现问题

但对于 ABA 问题来说,什么时候会出现 BUG 呢?

假设,我在银行向另一个账户转账 100元 ,当我按下转账按钮时,没有反应;然后又按了一次;此时产生了两个线程,去尝试进行扣款操作(假定按照 CAS 的方式进行扣款):

线程B 先扣款成功,线程A 发现钱对不上,就不进行操作;

但如果此时在 线程B 扣款成功的同时,线程C 向 我的账户转账了 100元;此时 线程A 就不知道 账户没有转账成功 还是 转账成功,又到账了;

对于 ABA 问题的解决方案:

1)约定数据变化时单向的(只能增加或者只能减少),不能时双向的(又是双向又是单向);

2)对于本身就必须要双向变化的数据(账户转账收款),可以引入一个 版本号-->版本号这个数字就是只能增加,不能减少;(转账1-->收款2--->转账3)

CAS本质上时 JVM 帮我们封装好的;

相关推荐
majingming12318 小时前
FUNCTION
java·前端·javascript
zopple18 小时前
常见的 Spring 项目目录结构
java·后端·spring
xuxie9920 小时前
N11 ARM-irq
java·开发语言
cjy00011120 小时前
springboot的 nacos 配置获取不到导致启动失败及日志不输出问题
java·spring boot·后端
wefly201721 小时前
从使用到原理,深度解析m3u8live.cn—— 基于 HLS.js 的 M3U8 在线播放器实现
java·开发语言·前端·javascript·ecmascript·php·m3u8
zhenxin012221 小时前
Spring Boot实现定时任务
java
小江的记录本21 小时前
【事务】Spring Framework核心——事务管理:ACID特性、隔离级别、传播行为、@Transactional底层原理、失效场景
java·数据库·分布式·后端·sql·spring·面试
sheji341621 小时前
【开题答辩全过程】以 基于springboot的校园失物招领系统为例,包含答辩的问题和答案
java·spring boot·后端
寂静or沉默21 小时前
2026最新Java岗位从P5-P7的成长面试进阶资源分享!
java·开发语言·面试
卓怡学长21 小时前
m289在线交友系统
java·spring·tomcat·maven·intellij-idea·hibernate