wshanshi:喵桑说,我总结完CAS就带我去吃羊蝎子火锅…干饭那必须整起啊…

一、什么是CAS?

CAS:Compare and Swap。从字面意义上来说,就是先进行比较,然后替换。

它是乐观锁思想的一种实现,尤其是在并发量大的业务场景下保证单个实例的原子性,使用较为频繁。java类库中java.util.concurrent.atomic包下一些方法,也均使用CAS处理。

二、悲观锁与乐观锁

CAS是乐观锁思想的一种体现,那乐观锁和悲观锁有什么区别呢?

2.1、悲观锁

悲观锁常见使用是synchronized修饰的代码块或者方法。

在操作数据之前加锁,直到数据操作完成,锁被释放之后,其它线程才可以操作该数据。比如,mysql数据库锁就是悲观锁。

2.2、乐观锁

数据操作不加锁,每次提交之前获取最新值与原获取值进行对比,数据未变更时操作,否则自旋。

2.3、区别

  • 乐观锁是并行的,悲观锁是串行的。

乐观锁:

悲观锁:

  • 乐观锁实质并未“加锁”,悲观锁是加了锁的(synchronized)。

三、CAS原理

Compare and Swap,比较并替换。说白了就是:在操作提交之前,与原获取到的值先进行比较,判断这个值有没有被修改。如果未被修改,操作修改。如果已被修改,则重新获取值,提交之前再比较…

举个栗子:关于《损友经常在群里偷偷改我的头衔》这件事。

线程a获取到我的信息,并操作将我的头衔由“三婶”改为了“王胖虎”。

之后线程b获取到我的头衔为“王胖虎”,又修改了“王胖虎”为“三婶”。

这是正常的一种非并发流程的体现,我们再来看下面一种情况:

假设线程a和线程b均获取到我的名字“三婶”。且线程a操作修改了“三婶”为“王胖虎”。

若a线程成功操作之后,线程b在修改提交前获取名称,发现实际读到的头衔是“王胖虎”。

对比预期值(三婶),发现"三婶"!=“王胖虎”(被修改了)。这时按照CAS原理,就会再次获取预期值(此时预期值为:王胖虎),且提交前获取内存值,进行对比…判断是否一致…

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

计算规则是:当需要更新一个变量的值的时候,仅当变量的预期值A(原获取)和内存地址V(提交前获取)中实际值相同的时候,才会把内存地址V对应的值替换成B。

如下图示例:

四、核心Unsafe类库

该类可直接操作内存,所以效率高。且Unsafe类和常量均使用final修饰,单例模式实现,不可继承。通过下图所示静态方法getUnsafe进行实例化,实例化在static块中操作的。


Unsafe可以设置读写某个属性,如下图所示。

volatile 保证了不同线程对共享变量操作的可见性,也就是说一个线程修改了 volatile 修饰的变量,当修改后的变量写回主内存时,其他线程能立即看到最新的值。

五、CAS优缺点

优点:在并发问题不严重的时候,性能方面比synchronized要快。

缺点:不能确保代码块的原子性。因为CAS机制确保的是一个变量的原子性操作,并不能保证整个代码块的原子性。如果多个变量共同进行原子性的更新操作,就需要用lock或者synchronized了。

5.1、自旋

假设线程a和线程b均获取到我的名字“三婶”。线程a操作修改了“三婶”为“王胖虎”,之后线程b在提交前获取名称,发现读到的是“王胖虎”。对比不一致,就会再次获取。

假如这个时候有个线程c把“王胖虎”改为了“胖虎”,线程b读取时又不一致了。这个时候就会一直获取,一直对比…

这种现象称为“自旋”。

5.2、ABA情况

还拿上述的栗子来说:

假设线程a和线程b均获取到我的名字“三婶”。然后线程a操作修改了“三婶”为“王胖虎”。

如果这个时候有个线程c成功操作:将“王胖虎”改为了“三婶”。线程b在提交前获取名称,发现读到的是“三婶”,它会以为“这个值并没有发生变化”。

但实质上,这个值可能是多次被修改后,恰巧变为了原始值的一种情况,也就是所谓的ABA.

六、如何避免ABA情况?

6.1、加版本号

每次操作compareAndSwap后给数据的版本号加1,再次compareAndSwap的时候不仅比较数据,也比较版本号,值相同,若是版本号不同,就不执行成功。

java.util.concurrent.atomic包中提供了AtomicStampedReference来解决该问题。


AtomicStampedReference 内部维护了一个 Pair的数据结构:reference(数据体)、stamp(版本)两个部分。该数据结构用volatile修饰,保证了线程可见性。

核心方法为:compareAndSet方法。该方法中,expectedReference:表示预期值,newReference:表示新的值,expectedStamp:表示预期版本号,newStamp表示新的版本号。


从数据和版本号两个方面来判断传入的参数是否符合 Pair 的预期,有一个不符合就返回false。

可以看到,这里底层也是使用了cas。预期值为“三婶”,版本号为0。新值为“王胖虎”,新版本号为1。

而casPair实质上调用的是UNSAFE.compareAndSwapObject()方法。

由此可见,AtomicStampedReference是通过加版本号来解决ABA问题的。对于加版本号,compareAndSwapObject只能对比交互一个对象,所以将数据和版本号放到一个对象里就可以解决问题了。

浅谈CAS,一篇就够了相关推荐

  1. 智能车浅谈——过程通道篇

    文章目录 前言 过程通道 模拟量输入通道 模拟量输出通道 开关量输入/输出通道 小结 模拟信号的调理 信号放大电路 滤波限幅电路 开关量信号调理 信号转换电路 滤波电路 保护电路 触点消抖 光耦隔离 ...

  2. 智能车浅谈——方向控制篇

    文章目录 前言 自动控制理论 人工控制系统 自动控制 方向控制 典型环节对应 典型环节分析 给定环节与给定量 比较环节与偏差量 控制环节与控制量 执行机构 舵机 PWM技术 舵机中值及限幅 转向控制 ...

  3. 智能车浅谈——控制规律篇

    文章目录 前言 计算机控制系统 常用控制规律 PID控制 比例(P)控制器 比例积分(PI)控制器 比例积分微分(PID)控制 位置式PID 增量式PID 数字PID控制算法的改进 PID参数整定 小 ...

  4. 智能车浅谈——电机控制篇

    文章目录 前言 运动控制系统 被控对象 执行机构 控制器 反馈环节 M法测速: T法测速 小结 直流调速系统 桥式可逆PWM变换器 (1)正向运行 (2)反向运行 总结 智能车系列文章汇总 前言 之前 ...

  5. 浅谈Java锁,与JUC的常用类,集合安全类,常用辅助类,读写锁,阻塞队列,线程池,ForkJoin,volatile,单例模式不安全,CAS,各种锁

    浅谈JUC的常用类 JUC就是java.util.concurrent-包下的类 回顾多线程 Java默认有几个线程? 2 个 mian.GC Java 真的可以开启线程吗? 开不了,点击源码得知:本 ...

  6. 智能车浅谈——手把手让车跑起来(电磁篇)

    文章目录 前言 材料准备 备赛组 车模 硬件 练习组 车模 硬件方案 整车原理 赛道信息获取及转向原理 工字电感 运放模块 转向原理 元素判断 电机及舵机控制原理 代码实现 效果欣赏 总结 17届完赛 ...

  7. 智能车浅谈——硬件篇

    目录 初识小车 硬件系统 1.电源系统 线性电源 开关电源 2.人机交互系统 3.MCU最小系统 4.传感器系统 摄像头 电感 编码器 5.驱动系统 机械结构 17届完赛代码 智能车系列文章汇总 前言 ...

  8. 智能车浅谈——抗干扰技术硬件篇

    文章目录 前言 干扰 什么是干扰 干扰窜入的主要途径 干扰的分类 硬件抗干扰技术 控制系统的电源保护技术 输入/输出传输线的抗干扰措施 I/O接口的抗干扰措施 接地技术 总结 智能车系列文章汇总 前言 ...

  9. 智能车浅谈——抗干扰技术软件篇

    文章目录 软件抗干扰技术 数字信号的抗干扰措施 数字输入信号软件抗干扰措施 数字输出信号软件抗干扰措施 数字滤波 算术平均值滤波 中值滤波 滑动平均滤波 归一化 差比和 CPU及程序的抗干扰措施 复位 ...

最新文章

  1. Clojure 入门
  2. Groovy中转换成java,Groovy将字符串类型转换为自定义类型的方法
  3. 如何配note,打补丁
  4. MYSQL BENCHMARK函数的使用
  5. 发布一个免费漂亮的仿Outlook风格、支持换肤的通用界面框架
  6. 从冷战到深度学习,一文看懂机器翻译发展史
  7. transformer中的多头注意力机制
  8. U盘被写保护,无法格式化
  9. 微信群控,云控?云控系统工作原理
  10. 二进制转十六进制(参考XYJ)
  11. 使用python爬取新浪微博的内容
  12. TesterHome android app 编写历程(四)
  13. 基于Robei:环境光传感器实验设计(及L298N模块控制LED灯板)
  14. python实现千牛客服自动回复语_千牛旺旺客服设置自动回复的技巧有哪些?总结性文章来啦...
  15. Python 中的正则表达式全部用法速查
  16. JSP停车场车位管理系统myeclipse开发oracle数据库BS模式java编程网
  17. 全国计算机等级三级网络技术试卷详解(一)
  18. php正则表达式检查匹配数字英文中文及手机号
  19. Linux的基本命令+深入一点的网址分享
  20. mysql handlersocket mongodb_MongoDB和MySQL HandlerSocket性能测试及其结果分析

热门文章

  1. python开三次方_python 3次方
  2. 自学Python之后如果不去公司上班,自己可以通过此技能挣什么钱?
  3. android视频动态壁纸app,短视频动态壁纸转换
  4. Linux笔记整理(1)系统的加载和main函数执行准备
  5. 吴恩达:22张图全解深度学习知识!
  6. JavaWeb自学笔记02
  7. grabber的使用_Google Grabber —使用PHP找出您的域名在Google中列出了多少页
  8. Springboot毕业设计管理系统毕业设计-附源码221032
  9. java汉字获取拼音的方法
  10. 中国信息导航网贤士招募令