当前位置: 首页 > news >正文

Java并发基石——CAS是如何实现的?

目录

一. 什么是CAS?

二. Java中关于 CAS 的 API 在哪里?

三. CAS API方法和参数解析

四. CAS的底层实现

五. CAS是如何保证多核线程安全的?

六. CAS的缺点?

七. 如何避免ABA问题?


一. 什么是CAS?

CAS的全称是 "CompareAndSwap",翻译过来就是 "比较和替换"。

CAS的操作包含三个操作数——内存地址,期望值,新值。如果内存位置的值与期望值匹配,那么处理器就会自动将该位置的值更新为新值;否则,处理器不做任何操作。无论哪种情况,它都会在CAS指令之前返回该位置的值。

CAS可以理解为 "我认为位置V的值应该是A,如果有该值,则将B放在这个位置;否则,不更改该位置的值,只告诉我这个位置现在的值即可"。

二. Java中关于 CAS 的 API 在哪里?

Java中 CAS 的 API 方法定义在 sun.misc.Unsafe 类中,Unsafe(不安全的)。

如下图所示就是该类中的部分代码,圈出来的三个方法 ,三个方法都有 native 修饰,这些方法不是由 Java 语言编写的,而是由C语言编写的;总之记住一点就行了,这些 native 本地CAS方法是用C语言编写的,通常也不是让我们 Java 程序员去调用使用的,更多见到它们是在源码中碰到它们。

三. CAS API方法和参数解析

CAS的三个方法作用相似,它们都有四个参数,我来说一下它们的作用。

compareAndSwapObject:比较并交换 Object 类型数据;

compareAndSwapInt:比较并交换 Int 类型数据;

compareAndSwapLong:比较并交换 Long 类型数据;

var1:方法要操作的对象;

var2:方法要操作的对象中属性的偏移量(举个例子,我们有一个 User 用户对象,在堆中存放,但我们只获取该 User 对象的其中一个属性值,就需要通过偏移量来获取,例如 user.name 获取用户名称属性);

var3:表示想要修改的数据属性当前值(意思就是改之前是什么值);

var4:表示想要修改的数据的修改值(意思就是想改成什么值);

四. CAS的底层实现

CAS的底层实现是通过调用 JNI 代码来实现的。

JNI 全称 java.native.interface ,翻译过来就是 Java本地接口方法,允许Java调用其它语言,而Java中的这三个CAS方法底层是用C语言编写的,通过C语言调用底层CPU,最终映射到CPU指令集上得以实现。

五. CAS是如何保证多核线程安全的?

现在的计算机大多都是多核心处理器,那么在此种情况下,系统执行CAS操作之前,会先去判断当前系统是否为多核心系统。如果是,就会给 "总线" 加锁,尽管有多个线程,但只有一个线程能给总线加锁成功,加完锁之后就会去执行CAS操作,也就是说CAS操作的原子性是平台级别的。而且只能有一个线程在同一时刻能够去执行CAS运算,无法多线程并行CAS操作,这样就解决了多核线程的安全问题。

六. CAS的缺点?

上面说到了CAS的操作原理,比较并替换,CAS操作时需要先判断先前的值是否发生变化,未变化则CAS,变化了则不执行CAS,如果说A线程在执行CAS操作之前,B线程将需要判断的值 a 改为了 b ,然后又从 b 改成了 a。那么当A线程再去执行CAS操作的时候,是可以执行成功的,因为它不管中间过程,只要我线程A在CAS时值未发生变化,就可以替换,但不能避免发生过变化不影响操作这种情况的发生。

举个简单的例子,事务A要去对数据库中的字段 num (假设当前值为1)做加一操作,事务B在事务A之前先去执行了加一操作,值变成了2,但是执行过程中发生了异常,事务B回滚,又从2回滚到了1,此时事务A再去对 num 进行加一操作时,是可以成功的,因为值没有发生改变。这种情况我们通常称为ABA问题。

七. 如何避免ABA问题?

为了解决ABA问题,在Java中,就引入了版本号这一说法,很简单,我们执行CAS操作时,不是会比较当前值和期望值是否相同吗?那我们就再加入一个版本号,对当前可能出现ABA问题的数据加上一个版本号,每当有一个线程对当前数据发生过修改,版本号都会做一次变换,即便又改回了原来的值,版本号也是不一致的。这样我们在执行CAS操作时,不仅要满足为当前值与期望值相等,还要满足当前版本号与期望版本号相同,只要有一个不同,CAS操作就不会成功,这样就可以避免ABA问题的出现。

http://www.cnnetsun.cn/news/3371721.html

相关文章:

  • ModTheSpire终极指南:5步快速上手《杀戮尖塔》模组加载器
  • 【LC-3汇编实战】从键盘中断到操作系统雏形:一次完整的中断机制构建
  • Java 异常体系全面总结详解
  • 张量网络系列(二 从图解到缩并:张量网络的运算艺术)
  • 手动修改spire.pdf
  • AiZynthFinder未来展望:AI在合成化学中的发展趋势
  • Gramine社区贡献指南:如何参与开源库操作系统项目开发
  • 终极窗口尺寸控制工具:WindowResizer让你完全掌控任意应用程序窗口
  • 微信聊天记录永久保存与分析完整指南:让珍贵对话永不丢失
  • 从原理到应用:一文读懂汽车电机的分类与选型
  • 艾尔登法环存档编辑器:从游戏挫折到自由掌控的智能解决方案
  • 精通Mac Mouse Fix:让普通鼠标在macOS上超越触控板的实战指南
  • 算法.动态规划.最少钱币数问题(Java,递归)
  • 2021 年开源 SLAM 算法集锦
  • 计算机毕业设计之基于SpringBoot框架的天气预报系统的设计与实现
  • list stream sort Comparator.nullsLast 避免空指针的正确用法
  • 数据库设计范式
  • 炉石传说终极自动化脚本:如何让日常任务效率提升73%
  • Fast-GitHub:网络边界革命,重塑中国开发者的GitHub体验
  • 从“AI辅助”到“AI共生”:一位特级教师用ChatGPT重构整学期大纲的真实日志(含每日Prompt迭代记录+学生反馈原始数据)
  • 如何在openEuler开源之夏项目中配置NFS存储与Kubernetes持久化存储
  • ct-oval 代码架构解析:深入理解安全漏洞扫描工具的模块化设计
  • 终极IPXWrapper指南:让Windows 10/11完美运行经典游戏联机
  • 5个核心功能:StreamFX完整指南 - 为OBS Studio打造专业级视觉效果
  • 工程结算技巧,吃透了够你用到老
  • OSS Browser:阿里云对象存储的桌面级管理革命
  • Flink CDC架构深度解析:构建企业级实时数据集成的最佳实践
  • 开发者必看:Earthdata Search本地部署与开发环境搭建指南
  • OnscripterYuri入门教程:如何快速在浏览器中运行视觉小说游戏
  • 纯NumPy手写计算图:从零构建可调试神经网络