JUC并发编程学习笔记——CAS个人理解

news2025/1/21 15:26:33

1. CAS引出

1.1 悲观锁

顾名思义,就是比较悲观的锁,总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁(共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程)。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。Java中synchronizedReentrantLock等独占锁就是悲观锁思想的实现。

1.2 乐观锁

反之,总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和CAS算法实现。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库提供的类似于write_condition机制,其实都是提供的乐观锁。在Java中java.util.concurrent.atomic包下面的原子变量类就是使用了乐观锁的一种实现方式CAS实现的。

1.3 对比

从上面对两种锁的介绍,我们知道两种锁各有优缺点,不可认为一种好于另一种,像乐观锁适用于写比较少的情况下(多读场景),即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。但如果是多写的情况,一般会经常产生冲突,这就会导致上层应用会不断的进行retry,这样反倒是降低了性能,所以一般多写的场景下用悲观锁就比较合适。

synchronized关键字会让没有得到锁资源的线程进入BLOCKED状态,而后在争夺到锁资源后恢复为RUNNABLE状态,这个过程中涉及到操作系统用户模式和内核模式的转换,代价比较高。

尽管JAVA 1.6为synchronized做了优化,增加了从偏向锁到轻量级锁再到重量级锁的过过度,但是在最终转变为重量级锁之后,性能仍然比较低。所以面对这种情况,我们就可以使用java中的“原子操作类”。

2. 乐观锁两种实现方式

上面其实已经说了悲观锁的实现方式了,即synchronizedReentrantLock。所以下面主要说说乐观锁的实现方式。主要有两种方式:

  • 1.版本号机制

    一般是在数据表中加上一个数据版本号version字段,表示数据被修改的次数,当数据被修改时,version值会加一。当线程A要更新数据值时,在读取数据的同时也会读取version值,在提交更新时,若刚才读取到的version值为当前数据库中的version值相等时才更新,否则重试更新操作,直到更新成功。就是通过version版本号作为一个标识,标识这个字段所属的数据是否被改变。

    在这里插入图片描述

    update table set x=x+1, version=version+1 where id=#{id} and version=#{version};  
    
  • 2.CAS算法

    compare and swap(比较与交换),是一种有名的无锁算法。无锁编程,即不使用锁的情况下实现多线程之间的变量同步,也就是在没有线程被阻塞的情况下实现变量的同步,所以也叫非阻塞同步(Non-blocking Synchronization)。

    而Atomic操作类的底层正是用到了“CAS机制”。AQS底层也用到了CAS机制。

3. CAS原理

CAS机制中使用了3个基本操作数:内存地址V,旧的预期值A,要修改的新值B

更新一个变量的时候,只有当变量的预期值A和内存地址V当中的实际值相同时,才会将内存地址V对应的值修改为B

当且仅当 V 的值等于 A时,CAS通过原子方式用新值B来更新V的值,否则不会执行任何操作(比较和替换是一个原子操作)。一般情况下是一个自旋操作,即不断的重试

从思想上来说,synchronized属于悲观锁,悲观的认为程序中的并发情况严重,所以严防死守,CAS属于乐观锁,乐观地认为程序中的并发情况不那么严重,所以让线程不断去重试更新。(自旋)

在java中除了上面提到的Atomic系列类,以及Lock系列类夺得底层实现,甚至在JAVA1.6以上版本,synchronized转变为重量级锁之前,也会采用CAS机制。

​ CAS通过调用JNI的代码实现,JNI: java Native Inter face,允许java调用其它语言。而compar eAndSwapxxx系列的方法就是借助“C语言”来调用cpu底层指令实现的。以常用的Intel x86平 台来说,最终映射到的cpu的指令为“cmpxchg”,这是一个 原子指令,cpu执行此命令时,实现比较并替换的操作!

4. CAS缺点

  1. CPU开销过大

    在并发量比较高的情况下,如果许多线程反复尝试更新某一个变量,却又一直更新不成功,循环往复,会给CPU带来很到的压力。

  2. 不能保证代码块的原子性

    CAS机制所保证的只是一个变量的原子性操作,而不能保证整个代码块的原子性。比如需要保证3个变量共同进行原子性的更新,就不得不使用synchronized了。

  3. ABA问题

    如果一个变量V初次读取的时候是A值,并且在准备赋值的时候检查到它仍然是A值,那我们就能说明它的值没有被其他线程修改过了吗?很明显是不能的,因为在这段时间它的值可能被改为其他值,然后又改回A,那CAS操作就会误认为它从来没有被修改过。这个问题被称为CAS操作的 "ABA"问题。

如果对数据的操作十分敏感,不容许出一点错,如银行转账、支付等,是不建议使用CAS加锁的,因为会存在ABA问题;如果在大并发情况下,CAS是不错的选择;

5. CAS底层源码简述

compareAndSet方法的实现很简单,只有一行代码。这里涉及到两个重要的对象,一个是unsafe,一个是valueOffset

什么是unsafe呢?Java语言不像C,C++那样可以直接访问底层操作系统,但是JVM为我们提供了一个后门,这个后门就是unsafe。unsafe为我们提供了硬件级别的原子操作

至于valueOffset对象,是通过unsafe.objectFiledOffset方法得到,所代表的是AtomicInteger对象value成员变量在内存中的偏移量。我们可以简单的把valueOffset理解为value变量的内存地址。

我们上面说过,CAS机制中使用了3个基本操作数:内存地址V,旧的预期值A,要修改的新值B。

而unsafe的compareAndSwapInt方法的参数包括了这三个基本元素:valueOffset参数代表了V,expect参数代表了A,update参数代表了B。正是unsafe的compareAndSwapInt方法保证了Compare和Swap操作之间的原子性操作。

6. CAS的ABA问题解决

真正要做到严谨的CAS机制,我们在compare阶段不仅要比较期望值A和地址V中的实际值,还要比较变量的版本号是否一致。

在Java中,AtomicStampedReference类就实现了用版本号作比较额CAS机制。

  • 1. java语言CAS底层如何实现? 利用unsafe提供的原子性操作方法。
  • 2.什么是ABA问题?怎么解决? 当一个值从A变成B,又更新回A,普通CAS机制会误判通过检测。利用版本号比较可以有效解决ABA问题。

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

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

相关文章

什么是 HTTP?

什么是 HTTP? 超文本传输协议 (HTTP) 是万维网的基础,用于通过超文本链接加载网页。HTTP 是应用程序层协议,旨在在联网设备之间传输信息,并在网络协议栈的其他层之上运行。HTTP 上的典型流涉及客户端计算机向服务器发出请求&…

2023CUPT第十四题 射流的折射 思路与解法

文章未完首先声明一点,这个题我还没想好最后的答案,欢迎交流(备注:博主今年不参加CUPT 博主去做电子设计大赛了!有电赛谁还玩CUPT啊)声明2:博主没有学过流体力学所以。。声明3:博主的…

[oeasy]python0045_转化为10进制数_int_integrate_integer_entire_整数

转化为10进制 回忆上次内容 上这次总结了四种进制 函数名对应单词进制类型数字事例前缀bin()binary20b11000010boct()octal80o1410ohex()hexadecimal160x610x?decimal1097无 十进制数 可以转化 为 其他进制 的 字符串状态 那反过来 其他进制形态的字符串 可以转化回 10进制…

Qt 自带标题处理方法思路

目录 需求 相关方法也有两种 1.只需要继承QAbstractNativeEventFilter类,从写放nativeEventFilter,并调用安装函数installNativeEventFilter 2.第二种是Qt提供的继承QWidget 重写bool nativeEvent(const QByteArray &eventType, void *message, …

RocketMQ事务消息原理简析

零、业务场景 在项目中,经常遇到这样一个场景,需要保证数据持久化和消息发送要么同时成功,要么同时失败。比如当用户在交易系统下了一个订单,购物车需要消费订单消息清除加购数据、积分系统需要变更用户积分、短信平台需要给买家…

如何选择显示检波器

之所以介绍频谱仪的显示检波器,是因为在宽带信号功率测试、功率谱密度测试及相噪测试等应用中,对显示检波器的选择有一定的要求。如果选择的检波器不合适,那么将无法准确完成测试。本文的目的也是想让初学者对这一块内容有更多的认识&#xf…

新手运营适合哪个跨境电商平台

很多企业的网站被收录却没有排名,关键词优化不上去,网站也没有什么流量,不断更新文章,即使是原创,也排不上去,这究竟是由于哪些原因造成的呢?米贸搜作为专业的SEO平台,整理了以下几种…

茶叶为啥那么贵?

60000个嫩芽才制作一斤好茶 茶叶采摘成本太高 如何通过机器人采茶? 趣讲大白话:茶叶贵是有道理滴 *********** 浙江理工大学智能采茶机器人 能自主识别茶树芽叶 控制机械臂进行精准采摘 芽叶识别准确率能达到82%左右 平均采摘速度2.5秒/颗 采摘成功率达…

【NI Multisim 14.0原理图的设计——简单电路设计】

目录 🥝🥝序言 🍍1.使用菜单命令 🍍2.右键快捷命令 🍍3. 使用快捷键 🥝🥝一、放置导线 🍍1.自动连线 🍍2. 手动连线 🍍 3.设置导线的属性 &#x1f3…

单目ADAS系列教程-相机基础篇

文章目录前言相机相关的4大坐标系像素坐标系与图像坐标系的转换图像坐标系与相机坐标系的转换相机坐标系与世界坐标系的转换相机畸变标定方法小结前言 PS:本文仅讨论针孔模型相机,其余类型相机并不涉及! 相机基础包括相机内参,相…

(1)WireShark

1.工具简介(1)定义WireShark是一个网络封包分析软件。网络封包分析软件的功能是抓取网络封包,并尽可能显示出最为详细的网络封包资料。使用WinPACA作为接口,直接与网卡进行数据报文交换。(2)嗅探器工作原理收集:从网络线缆上收集原始二进制数…

Redis客户端命令基础操作二

目录 Redis中五种常用的结构: 字符串:String 字符串可以存储三种类型的值:字节串、整数、浮点数 列表:List Redis中五种常用的结构: 字符串(string)、列表(list)、集合(set)、散列(hash)、有序集合(zset)客户端基础命令操作 字…

Java项目:旅游网站管理系统设计和实现(java+springboot+jsp+mysql+spring)

源码获取:博客首页 "资源" 里下载! 运行环境: java jdk 1.8 IDE环境: IDEA tomcat环境: Tomcat 7.x,8.x,9.x版本均可 主要功能说明: 管理员角色包含以下功能:管理员登录,用户管理,旅游路线管…

集装箱号识别率99.98%+实时返回结果高泛化,全球领先飞瞳引擎集装箱识别检测云服务全球三千企业用户,集装箱信息识别铅封识别免费

飞瞳引擎™AI集装箱识别检测云服务全球三千企业使用,顶尖AI科技集装箱号识别率99.98%以上高泛化性高鲁棒性,可二次开发或小程序拍照使用,集装箱号铅封号识别API免费实时返回结果。CIMCAI是全球规模领先应用范围领先,核心技术领先的…

帆软数据决策平台连接SAP RFC实例

一、介绍由于SAP ABAP开发出来的报表很单一,形式很有限,而且调整报表格式和形式都显得特别的鸡肋,所以现在将SAP系统通过RFC接口模式接入到帆软报表数据决策平台下展示。本文将详细介绍如何将数据从SAP传输到帆软平台上。二、准备工作首先得先…

色氨酸代谢与肠内外健康稳态

谷禾健康 色氨酸(Tryptophan,简称 Try)是人体必需氨基酸,也是唯一含有吲哚结构的氨基酸,由食物尤其膳食蛋白质提供,是正常细胞稳态所必需的,是维持细胞生长和协调机体对环境和饮食线索的反应&am…

Java基础06——字符串

Java基础06——字符串一、String1. 字符串特点2. 创建字符串对象的两种方式直接赋值new3. 字符串常用方法a. 比较b. 遍历c. 截取d. 替换二、StringBuilder1. StringBuilder概述2. StringBuilder构造方法3. StringBuilder常用方法三、StringJoiner1. StringJoiner概述2. StringJ…

mysqldump binlog增量恢复会导致数据重复

1. mysqldump时间很长,导出第一个表和导出最后一个表的时间可能过去几个小时,如果期间不锁库,使用binlog增量恢复的时候,如果从备份开始的binlog开始恢复,备份期间别的表的改动通过应用binlog日志会再次被应用一次。导…

如何做好舆情管控,TOOM舆情监控服务工作经验总结

网络舆情监测剖析是实时控制网络舆情动态的一项基本工作,也是妥当处置网络有害信息,制定有效宣扬策略,准确引诱舆论导向的主要前提与根据 。接下来简单了解如何做好舆情管控,TOOM舆情监控服务工作经验总结。 一、如何做好舆情管控…

priority_queue 优先级队列(堆) 的模拟实现

目录 一、优先级队列的模板参数列表 二、优先级队列的构造函数(建堆 nlogn) AdjustDown() 向下调整: 建堆的时间复杂度: 三、pop()接口 (堆顶元素的删除: logn) 四、push()接口 &#xff…