深入理解CAS

news2024/11/29 22:46:43

目录

  • 深入理解CAS
      • CAS中的引入
      • 什么是CAS?
      • CAS原理——Unsafe类
      • CAS优点
      • CAS缺点
      • ABA问题
      • 解决ABA问题

深入理解CAS

 

CAS中的引入

我们知道我们使用Volatile可以保证可见性,但不保证原子性,那么,如果我们不使用Lock锁和synchronized,我们该如何保证添加了volatile关键字的共享变量的原子性呢?

解决方案:我们可以使用Java中java.util.concurrent.atomic包下的原子类,来解决我们的原子性问题,而他们就是使用了CAS来实现的。
 

什么是CAS?

CAS的全称是:Compare And Swap(比较),是CPU广泛支持的一种对内存中共享数据进行操作的一种特殊的指令,CAS可以将比较和交换转换成原子操作,这个原子操作由CPU保证。

 

CAS原理——Unsafe类

我们根据源码可知,我们的AtomicInteger类中有一个Unsafe类。我们知道Java是无法直接操作内存的,但是我们Java可以调用C++,而C++是可以操作内存的。比如我们的native 方法,而这个Unsafe类就是Java的后门,Unsafe类让Java拥有了像C语言的指针一样操作内存空间的能力,我们可以通过这个类来进行内存的操作。

我们的原子类AutomicInter.incrementAndGet(),底层是调用了Unsafe类的incrementAndAddInt()方法

 
在这里插入图片描述
 
Unsafe类中的getAndAddInt()方法底层使用的就是CAS,并且这个方法使用的是自旋锁。CAS操作依赖3个值

  • 内存中的值V

  • 旧的预估值X

  • 要修改的值B

  首先这个方法先会通过unsafe.getIntVolatile(Obj,ValueOffset),传进去automicInter对象,然后根据偏移量来获取内存中automicInteger中的value,然后赋值给var5,然后再根据自旋锁判断内存中的value值(也是再一次通过上述的方法获取)var1,var2,然后通过与var5进行比对,如果值相同,则将后面的var5+var4(1)赋值给value。

我们来举例一个多线程例子:比如有两条线程t1、t2,

  • t1:在通过getInvolatile()方法之后获取了内存中automicInteger中的value。
  • 而这个时候,t2:走了getAndAddInt()的整个流程,这个时候,内存中的值已经+1了
  • t1:来到while中判断,结果发现内存中的值和var5不相同,则重新走do这个流程重新获取内存中的内存值再赋值给var5,再重新判断。

这个流程就是CAS的原理。

 
在这里插入图片描述
 

 

CAS优点

  • 基于内存操作,效率很高。
  • 因为CAS底层使用的是自旋锁、乐观锁的思想,所以线程不会陷入阻塞状态,效率很高。

 

CAS缺点

CAS虽然能保证我们的原子性操作,但是会出出现以下的问题:
1、循环时间的开销较大:对于资源竞争较为激烈的场景,如有多个线程,这个时候CAS自旋的概率就会比较大,从而浪费CPU资源,效率可能会低于synchronized。
2、只能保证一个共享变量的原子操作:当对一个共享变量执行操作时,我们可以使用循环CAS的方式来保证原子操作,但是对多个共享变量操作时,循环CAS就无法保证的原子性,这个时候就可以用锁。
3、可能会出现ABA问题。
 

ABA问题

什么是ABA问题?
ABA问题一句话概括就是(狸猫换太子),假设两条线程去操作同一个资源,线程A和线程B,线程A想通过CAS把资源1改成2,而线程B拿到资源后把资源从1改为3,又把3改为1,而此时线程A还以为1是以前的资源,其实线程A拿到的值已经被线程B动过手脚了,这就是ABA问题。

 

解决ABA问题

1、我们可以使用原子引用AtomicRefence来解决ABA问题。

什么是原子引用AtomicReference?说白了原子引用就是带版本号的原子操作。
AtomicStampedReference atomicStampedReference = new AtomicStampedReference(初始值,时间戳);
这个时间戳可以看成是版本号,如果我们把它设置为1,我们每次修改,我们都需要把这个值往上题,每次有人动了这个值,我们就知道这个值已经被人动过了,这根乐观锁是一样的原理。

在这里,如果我们使用的是 int 的包装类型 Integer ,那么我们就需要注意,我们的初始值不能设置大于128的,如果大于128的会出现CAS产生失败的现象。这是有一个大坑。

在阿里巴巴的开发手册中发现,Integer 采用了对象缓存机制,在-128至127之间赋值,Integer 对象会在IntegerCache.cache中获取,会复用已有的对象,但是这个区间以外的所有数据,都会在堆上产生,并不会复用已有的对象,这就导致了我们的引用不是同一个值,所有会修改失败。

 

 
 
 
  
  
  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/152541.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

机器学习之XGBoost模型学习

1.划分数据集函数train_test_split以及数据的加载: python机器学习 train_test_split()函数用法解析及示例 划分训练集和测试集 以鸢尾数据为例 入门级讲解_侯小啾的博客-CSDN博客_train_test_split 还有这篇文章,解析的清除: https://com…

2022 年度中国时序数据应用创新奖公布,涉及工业互联网、车联网等多个行业

随着新兴技术的快速发展,越来越多的企业开始以技术的融合创新来推动业务的数字化智能化转型,其中也诞生了很多成功的应用实践案例。2023 年 1 月 9 日,北京涛思数据科技有限公司(TAOS Data) 正式公布「2022 年度中国时序数据应用创新奖」获奖…

【路径规划】基于D星算法实现栅格地图机器人路径规划

目录算法介绍栅格地图代码运行效果算法介绍 A* 在静态路网中非常有效(very efficient for static worlds),但不适于在动态路网,环境如权重等不断变化的动态环境下。 D是动态A(D-Star,Dynamic A Star) 卡内…

nodejs 如何实现自动化部署?

什么是自动化部署 我接触到的自动化部署概念最早是在 Vercel 上提供的,Vercel 可以提供和 github 联动的功能,通过和你自己的 github 上的某个库建立‘链接’,当你 commit 到 github 远程库时就可以自动部署,Vercel 会帮你完成以…

腾龙健康冲刺A股上市:计划募资10亿元,彭学文家族色彩浓厚

近日,广州腾龙健康实业股份有限公司(下称“腾龙健康”)预披露招股书,准备在深圳证券交易所主板上市。 本次冲刺上市,腾龙健康计划募资10.13亿元,其中4.09亿元用于水疗按摩池配件生产基地升级项目&#xff0…

数据可视化做出的个人年终总结报告,高颜值更高更具说服力

年终总结与个人业绩、晋升、加薪、离职或留任密切相关。聪明人利用年终报告来总结自己的成就和获得资源,领导者也可以从年终报告看出员工的成长和变化。例如我用可视化互动平台,智能分析做出的公司年终总结报告,高颜值高说服力,领…

Java异常的分类和注意点

异常体系结构 Error与Exception Error是程序无法处理的错误,它是由JVM产生和抛出的,比如OutOfMemoryError、ThreadDeath等。这些异常发生时,Java虚拟机(JVM)一般会选择线程终止。 Exception是程序本身可以处理的异常…

国内外BI数据分析工具做报表有多大区别?

有什么样的土壤就会早就什么样的产品。国内外企业对报表的不同需求导致了国内外BI数据分析工具做表格时的巨大差异,这也是很多时候国外BI数据分析工具在中国水土不服,遭遇口碑体验两极化的一大原因。下面就来简单看看国内外BI数据分析工具做表格时的不同…

【前端】Vue项目:旅游App-(10)city:以indexBar的形式显示数据

文章目录目标过程与代码分析数据并展示封装到一个组件添加indexBar样式修改优化tab栏的切换效果总代码修改或新增的文件common.csscity.vuecurrentGroupCity.vuemain.js目标 上一篇显示了服务器中的数据:【前端】Vue项目:旅游App-(9&#xf…

(九)devops持续集成开发——jenkins流水线发布一个docker版的前端vue项目

前言 本节内容主要介绍如何使用jenkins的流水线发布一个docker版的前端项目。关于本节内容中使用到的jenkins的组件,请参考往期博客内容,自行安装。我们使用NodeJS完成前端项目的编译安装,使用ssh组件完成编译后工程的传输,以及d…

Allegro如何快速复制铜皮到其它层面的两种方法详细操作指导

Allegro如何快速复制铜皮到其它层面的两种方法详细操作指导 在做PCB设计的时候,通常需要复制一个做好的铜皮到其它层面,如下图 需要把L3层的铜皮复制到其它的内层 Allegro支持快速将铜皮拷贝到其它层,下面介绍两种方法,具体操作如下 方法一 选择Edit

快速生成100万条数据并存入mysql数据库(1):游戏人物数据

最近正在一直苦恼如果去获取更多的数据以用来进行后期的查询和进行测试,发现了Navicat这个不错的宝藏,他可以一下子根据你数据库里面创建的各种各样的字段和约束创建出各种各样你自己想要的大量数据,当然这些数据非真实数据而是虚拟数据&…

Swin Transformer原理详解篇

🍊作者简介:秃头小苏,致力于用最通俗的语言描述问题 🍊往期回顾:CV攻城狮入门VIT(vision transformer)之旅——近年超火的Transformer你再不了解就晚了! CV攻城狮入门VIT(vision transformer)之旅——VIT原…

Nacos多级服务存储模型, NacosRule负载均衡规则入门

👳我亲爱的各位大佬们好😘😘😘 ♨️本篇文章记录的为 NacosRule负载均衡规则 相关内容,适合在学Java的小白,帮助新手快速上手,也适合复习中,面试中的大佬🙉🙉🙉。 ♨️如…

【毕设必备】Python制作GUI学生管理系统,这把直接稳赢

前言 最近有个朋友说,能不能让我搞个学术上管理系统出来,想自己用用,好朋友嘛,那就搞个给他用用咯 之前还有个小朋友说,想弄个出来发给老师,让老师表扬一下自己哈哈哈 话说,这个还是可以做毕…

基于微信小程序的高校毕业论文管理系统小程序

文末联系获取源码 开发语言:Java 框架:ssm JDK版本:JDK1.8 服务器:tomcat7 数据库:mysql 5.7/8.0 数据库工具:Navicat11 开发软件:eclipse/myeclipse/idea Maven包:Maven3.3.9 浏览器…

深入剖析B端产品权限设计-功能权限设计篇

权限设计是B端产品永远绕不开的一个课题,良好的产品权限设计架构是支撑企业复杂业务的基础与关键。接下来会分两篇文章剖析产品权限管理,一篇分享功能权限管理,一篇分享数据权限管理。一、什么是权限管理权限管理,一般指根据系统设…

1.9第三周星期一

LAMP环境搭建 1. 下载 yum install gcc gcc-c cmake ncurses ncurses-devel bison wget openssl-devel -y rpm -qa | grep mysql rpm -qa| grep mariadb yum install gcc gcc-c cmake ncurses ncurses-devel bison wget openssl-devel -y 2.建立mysql 组&#xff0c;<--新…

Linux常用命令与常见操作:重启服务器

Linux系统运维经验 Xshell prompt与Linux 【Linux】【CentOS】xshell连接Linux虚拟机 Linux linux常用命令 常见操作 升级补丁后重启服务器 cd /opt/zc/ nohup ./startup-linux.sh &有36、37两台服务器&#xff0c;37直接执行上面2条语句即可重启成功。 36这台服务器…

【计算机网络】网络基础

目录前言一、计算机网络发展二、初识“协议”1. 协议的概念2. 协议分层三、OSI七层模型四、TCP/IP五层(四层)模型五、网络传输基本流程1. 网络传输流程图2.数据包封装和分用六、网络中的地址管理1. IP地址2. MAC地址前言 本文是博主首次学习网络知识后进行的总结&#xff0c;文…