死锁-CAS下ABA问题及优化方案

真实业务场景展现CAS原理的ABA问题及解决方案 文章目录阅读提示CAS原理、ABA问题介绍真实业务场景如何解决ABA问题CAS学习总结 阅读提示 本文将借助开保险柜的业务场景重点阐述误用AtomicBoolean引起的ABA问题,以及解决方案。基于此,请先深入理解CAS原理,以及其会产生的ABA问题。关于CAS原理和ABA问题的优秀博客已经存在很多,所以本文只简单介绍CAS原理,希望读者有此基础。 CAS原理、ABA问题介绍 CAS(Compare and Swap)是一种乐观锁机制。CAS有3个操作数,预期值A,内存值V,要修改的新值B。当且仅当预期值 阅读详情

一、并发业务场景

库存业务,stock(sid, num),其中:

  • sid为库存id

  • num为库存值

如上图所示,两个并发的查询库存操作,同时从数据库都得到了库存是5。

接下来用户发生了并发的库存扣减动作:

如上图所示:

  • 用户1购买了3个库存,于是库存要设置为2

  • 用户2购买了2个库存,于是库存要设置为3

这两个设置库存的接口并发执行,库存会先变成2,再变成3,导致数据不一致(实际卖出了5件商品,但库存只扣减了2,最后一次设置库存会覆盖和掩盖前一次并发操作)

二、不一致原因分析

出现数据不一致的根本原因,是设置操作发生的时候,没有检查库存与查询出来的库存有没有变化,理论上:

  • 仅库存为5的时候,用户1的库存设置2才能成功

  • 仅库存为5的时候,用户2的库存设置3才能成功

实际执行的时候:

  • 库存为5,用户1的set stock 2确实应该成功

  • 库存变为2了,用户2的set stock 3应该失败掉

三、CAS优化

大家常说的“Compare And Set”(CAS),是一种常见的降低读写锁冲突,保证数据一致性的乐观锁机制。

针对上述库存扣减的例子,CAS升级很容易,将库存设置接口执行的SQL:

update stock set num=$num_new where sid=$sid

升级为:

update stock set num=$num_new where sid=$sid and num=$num_old

即可。

四、什么是ABA问题

CAS乐观锁机制确实能够提升吞吐,并保证一致性,但在极端情况下可能会出现ABA问题。

什么是ABA问题?

考虑如下操作:

  • 并发1(上):获取出数据的初始值是A,后续计划实施CAS乐观锁,期望数据仍是A的时候,修改才能成功

  • 并发2:将数据修改成B

  • 并发3:将数据修改回A

  • 并发1(下):CAS乐观锁,检测发现初始值还是A,进行数据修改

上述并发环境下,并发1在修改数据时,虽然还是A,但已经不是初始条件的A了,中间发生了A变B,B又变A的变化,此A已经非彼A,数据却成功修改,可能导致错误,这就是CAS引发的所谓的ABA问题。

库存操作,出现ABA问题并不会对业务产生影响。

再看一个堆栈操作的例子:

并发1(上):读取栈顶的元素为“A1”

并发2:进行了2次出栈

并发3:又进行了1次出栈

并发1(下):实施CAS乐观锁,发现栈顶还是“A1”,于是修改为A2

此时会出现系统错误,因为此“A1”非彼“A1”

五、ABA问题的优化

ABA问题导致的原因,是CAS过程中只简单进行了“值”的校验,再有些情况下,“值”相同不会引入错误的业务逻辑(例如库存),有些情况下,“值”虽然相同,却已经不是原来的数据了。

优化方向:CAS不能只比对“值”,还必须确保的是原来的数据,才能修改成功。

常见实践:“版本号”的比对,一个数据一个版本,版本变化,即使值相同,也不应该修改成功。

库存的并发读写例子,引入版本号的具体实践如下:

(1)库存表由

stock(sid, num)

升级为

stock(sid, num, version)

(2)查询库存时同时查询版本号

select num from stock where sid=$sid

升级为

select num, version from stock where sid=$sid

假设有并发操作,都会将版本号查询出来

(3)设置库存时,必须版本号相同,并且版本号要修改

旧版本“值”比对CAS

update stock set num=$num_new where sid=$sid and num=$num_old

升级为“版本号”比对CAS

update stock set num=$num_new, version=$version_new

 where sid=$sid and version=$version_old

此时假设有并发操作,第一个操作,比对版本号成功,于是把库存和版本号都进行了修改。

同时存在的第二个并发操作,比对版本号发生了变化,也是库存应该修改失败。

六、总结

  • select&set业务场景,在并发时会出现一致性问题

  • 基于“值”的CAS乐观锁,可能导致ABA问题

  • CAS乐观锁,必须保证修改时的“此数据”就是“彼数据”,应该由“值”比对,优化为“版本号”比对

经典的ABA问题与解决方法 来自blog考虑如下操作: 并发1(上):获取出数据的初始值是A,后续计划实施CAS乐观锁,期望数据仍是A的时候,修改才能成功 并发2:将数据修改成B 并发3:将数据修改回A 并发1(下):CAS乐观锁,检测发现初始值还是A,进行数据修改 上述并发环境下,并发1在修改数据时,虽然还是A,但已经不是初始条件的A了,中间发生了A变B,B又变A的变化,此A已经非彼A,数据却成功修改,可能导致错误,这就是CAS引发的所谓的ABA问题。这个应该就是产生ABA问题的真正原因。 阅读详情

相关推荐

并发编程实战:原子变量类的性能优化与应用场景

本文深入探讨了原子变量类在并发编程中的性能优化与应用场景。通过对比synchronized锁,原子变量类利用CAS指令实现非阻塞同步,显著提升吞吐量。文章分享了避免伪共享、批量操作等实战技巧,并解析了高性能计数器、状态标志管理等典型应用场景,帮助开发者优化高并发系统性能。

weixin_29292535的博客 191

ABA问题

ABA问题一.概述:二.什么是ABA问题?三.ABA问题的解决:原子引用:(存在ABA问题)带版本号的原子引用(解决ABA问题) 一.概述: ABA问题是在多线程并发的情况下,发生的一种现象。上一次记录了有关CAS操作的一些知识,CAS通过比较内存中的一个数据是否是预期值,如果是就将它修改成新值,如果不是则进行自旋,重复比较的操作,直到某一刻内存值等于预期值再进行修改。而ABA问题则是在CAS操作中存在的一个经典问题,这个问题某些时候不会带来任何影响,某些时候却是影响很大的。 二.什么是ABA问题? 理解一

huangquan__的博客 1万+

volatile和原子类及CAS、synchronized、Lock、死锁及其解决方式

volatile

の博客 502

并发编程中的 ABA问题是什么?如何解决?

ABA问题的名字来源于一个简单的场景:假设有一个变量最初的值是 A,一个线程读取到这个值 A后,准备进行一些操作,在此期间,另一个线程将这个值从 A改为 B,然后又改回 A。对于第一个线程而言,虽然它再次检查时变量的值仍然是A,好像什么都没有发生过,但实际上这个变量已经被其他线程修改过。这个问题之所以被称为ABA,是因为变量经历了一个从 A到 B再回到 A的过程。

2403_88969259的博客 1230

软硬件协同设计的大小端问题

缘起 最近需要在soc系统内做协处理器,加速AES加密运算,寄存器一次读取32bit,AES一次处理128bit,因此在数据拼接的时候,需要考虑大小端的问题,特来记录一番。 一、什么是大小端 大小端的问题发生在寄存器和内存间传递数据,这点非常重要,很多地方简单地说是数据存储方式,其实不准确。追根溯源,大小端问题是在设计load,store指令的时候考虑的,因此本质是寄存器和内存交互的问题,其他地方不会发生。 比如c语言里定义一个变量int a=ox1234,那么查看在线汇编平台的对应汇编代码: # 给2号寄

http://www.icfgblog.com/ 612

椭圆 —— 从理论推导到最小二乘法拟合

前言 椭圆在高中数学里就开始提到,都是从标准方程开始如: x2a2+y2b2=1(a>b>0) \frac{x^2}{a^2}+\frac{y^2}{b^2}=1(a>b>0) a2x2​+b2y2​=1(a>b>0) 其中 aaa 为椭圆的长轴,bbb 为椭圆短轴。如长轴为 111 ,短轴为 0.50.50.5 的椭圆可以这样画出 ezplot('x^2/1^2 + y^2/0.5^2 = 1',[-1.5 1.5 -1 1]) grid on; 标准方程可以很方便

学徒浩子 2万+

CAS的ABA问题,ABA问题会导致什么后果?

ABA问题会导致什么后果?(以下为转载) https://blog.youkuaiyun.com/wufaliang003/article/details/78797203 一、并发业务场景 库存业务,stock(sid, num),其中: sid为库存id num为库存值 如上图所示,两个并发的查询库存操作,同时从数据库都得到了库存是5。 接下来用户发生了并发的库存扣减动作: ...

祁东握力的博客 1万+

RK3399平台入门到精通系列讲解 - 总目录

欢迎大家来到内核笔记的《RK3399平台开发入门到精通系列讲解》,开始前博主先列出RK3399平台学习的大纲,同时这也可以作为大家学习RK3399内核与安卓框架的参考。下面蓝字都是传送门,点击进入即可:...

内核笔记 10万+

从死锁到秒杀:Java 并发编程的 7个核心陷阱与突围方案

ThreadLocal 的内部结构是 Thread→ThreadLocalMap→Entry(key 为 ThreadLocal,value 为存储的值),Entry 是弱引用,当 ThreadLocal 被回收后,key 变为 null,但 value 仍被强引用,若线程长期存活(如线程池中的核心线程),value 将永远无法被回收。ThreadLocal 用于存储线程私有变量,但在使用线程池时,线程会被复用,若不及时清理 ThreadLocal 中的值,可能导致内存泄漏。

weixin_44075173的博客 941

C/C++跳动的爱心(完整代码)

C语言实现跳动的爱心的完整代码。

AIGC 5842

斑马算法优化变分模态分解ZOA-VMD数字信号去噪(优化K值 alpha值)【含Matlab源码 4887期】

斑马算法优化变分模态分解ZOA-VMD数字信号去噪(优化K值 alpha值) 完整的代码,包运行;运行操作视频见优快云资源!适合小白!

订阅付费专栏Matlab(奶茶价版),可赠送奶茶价版付费专栏指定代码1份; 810

关于CAS等原子操作

#关于CAS等原子操作 在开始说无锁队列之前,我们需要知道一个很重要的技术就是CAS操作——Compare & Set,或是 Compare & Swap,现在几乎所有的CPU指令都支持CAS的原子操作,X86下对应的是 CMPXCHG 汇编指令。有了这个原子操作,我们就可以用其来实现各种无锁(lock free)的数据结构。 这个操作用C语言来描述就是下面这个样子:意思就是说,看一看内存*reg里的值是不是oldval,如果是的话,则对其赋值newval。 int compare_and_

thelastsinger的博客 422

一文探讨视频秒开:m3u8视频格式与视频秒开优化

秒开指的是,一秒内成功加载的播放数/播放总数。本意是想对比一下m3u8与mp4视频格式,并了解m3u8格式优缺点,以确定一个大概优化方向。但对m3u8做简单了解后,觉的m3u8可能是一个优化方向。

bjxiaxueliang的CODING小栈 2万+

以下是一条原创的中文文章标题,围绕关键词**Java****「Java多线程编程中CAS算法的动态锁

以`AtomicInteger.compareAndSet`为例,其底层调用汇编指令如`cmpxchg`实现:当线程A调用`compareAndSet(3,4)`时,首先从内存加载当前值CV,若CV等于期望值3,则将目标值4写回内存;这一过程全程在CPU内核完成,确保操作的原子性,避免线程间可见性污染。某键值存储系统的分段锁实现了锁字段的缓存对齐:通过预留128字节对齐的padding区,并将每个分段锁占据独立缓存行,彻底消除跨核CAS操作争抢共享缓存行的开销,观测到吞吐量提升23%。

gxgCBOVD的博客 314

【第1章>第9节】基于FPGA的图像开运算处理算法的Verilog实现

本文介绍了基于FPGA的开运算图像处理实现方法。主要内容包括:1)输入图像二值化处理,通过阈值将灰度图像转换为二值图像;2)数据缓存与窗口提取,使用寄存器数组缓存5行图像数据并构建5×5处理窗口;3)腐蚀运算逻辑,判断窗口内是否全为白色像素;4)膨胀运算逻辑,检测窗口内是否存在白色像素。最后给出了Verilog实现方案,通过级联腐蚀和膨胀模块完成开运算处理。该方法可用于FPGA图像处理算法开发。

MATLAB,verilog,python,opencv,tensorflow,caffe,C,C++ 313

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

并发 - 锁机制

乐观锁总是假设最好的情况,认为共享资源每次被访问的时候不会出现问题,线程可以不停地执行,无需加锁也无需等待,只是在提交修改的时候去验证对应的资源是否被其它线程修改了。一般使用版本号机制或 CAS 算法,在 Java 中java.util.concurrent.atomic包下面的原子变量类(比如AtomicInteger、LongAdder)就是使用了乐观锁的一种实现方式 CAS 实现的。版本号机制。

weixin_43191747的博客 1156

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

从死锁到秒杀:Java 并发编程的 7个核心陷阱与破局指南(附实战代码)

HashMap线程不安全,Hashtable全表锁性能差,ConcurrentHashMap(JDK1.8+)采用 CAS + 同步块实现分段锁,读操作无锁,写操作仅锁定当前节点,性能远超传统同步容器。但线程池中的线程不会自动销毁,必须手动清理。CAS 操作在多线程下可能出现 “ABA 问题”:线程 1 读取值为 A,线程 2 将 A 改为 B 再改回 A,线程 1 的 CAS 会误判为 “未被修改”。因为线程池的线程是复用的,ThreadLocal变量若未及时清理,会随线程长期存在。

weixin_44075173的博客 456

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

Java 并发编程挑战:从原理到实战的深度剖析与解决方案

本文深度解析 Java 并发编程的核心挑战,涵盖内存可见性、竞态条件、死锁、线程池滥用及 ABA 问题,提出基于并发工具类、锁优化、异步编程与无锁化的解决方案。结合性能监控工具与调优策略,总结最小化同步范围、避免显式线程管理等最佳实践,助力开发者构建高效稳定的并发系统。

大模型全栈工程师 · Thanks_ks 1509

多线程(四)

本文简单介绍了CAS, ABA问题, 死锁, 线程池以及ConcurrentHashMap

Cwb154748854的博客 244

Java中的锁居然有这么多!

死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。线程1 拥有 资源A 的锁,线程2 拥有 资源B 的锁,但是线程1在持有A锁的情况下,还想拥有B锁。可以发现这个过程中 线程1 在修改值的时候,线程2,3已经修改过变量a的值了,但是它毫不知情~为啥是 Java 中的锁呢, 因为 锁的种类 也有很多的,像我们平时使用的。独自占有锁,不和其他线程共享~ 😄 和 互斥锁,排他锁,悲观锁 同义。

m0_72885838的博客 107

java锁

1 锁升级 无锁 - 偏向锁 -轻量级锁(自旋锁)-重量级锁 无锁 - 对象刚创建的时候是无锁状态 偏向锁 - 使用锁的线程只有一个,偏向锁的目标是,减少无竞争且只有一个线程使用锁的情况下,使用轻量级锁产生的性能消耗。轻量级锁每次申请、释放锁都至少需要一次CAS,但偏向锁只有初始化时需要一次CAS。 有多线程争用锁, 锁升级为轻量级锁 - 每个线程有自己的LockRecord在自己的线程栈上,...

weixin_44655181的博客 207

【Java并发进阶3】synchronized 优化过程,锁策略到底层实现,CAS相关问题

本文介绍了Java中synchronized的优化过程和常见锁策略。synchronized锁升级过程包括无锁、偏向锁、轻量级锁和重量级锁四个阶段,且只能升级不能降级。常见的锁策略包括乐观锁/悲观锁、重量级锁/轻量级锁、自旋锁、公平锁/非公平锁、可重入锁/不可重入锁以及读写锁,每种策略都有其适用场景和优缺点。此外,文章详细讲解了CAS(比较并交换)机制,包括其原理、应用场景和ABA问题及其解决方案。CAS通过原子操作实现无锁同步,适用于低竞争环境,但需要注意ABA问题,可通过引入版本号机制解决。

m0_58718491的博客 409

面试必备-行锁、表锁 - 乐观锁、悲观锁的区别和联系(史上最全)

锁 悲观锁 总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁(共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程)。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。Java中synchronized和ReentrantLock等独占锁就是悲观锁思想的实现。 or 总是认为多用户访问数据库时会产生并发冲突,因此需要消除所有可能会产生冲突的操作 共享锁(Sh

yxg520s的博客 3845

synchronized同步锁特性

synchronized同步锁特性

asmall_cat的博客 441

JUC(个人笔记三)

1、什么是JMM(java内存模型)? 2、它干嘛的?:官方,其他人的博客,对应的视频 3、它该如何学习?

eternally_zh128@sina.com的博客 247
上一篇: webservice-TCP三次握手四次挥手
下一篇: gitHub创建分支命令操作
满地节操1
博客等级 码龄10年 12粉丝 36原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值