【多线程】CAS 详解

CAS 详解

  • 一. 什么是 CAS
  • 二. CAS 的应用
    • 1. 实现原子类
    • 2. 实现自旋锁
  • 三. CAS 的 ABA 问题
  • 四. 相关面试题

一. 什么是 CAS

CAS: 全称Compare and swap,字面意思:”比较并交换“

一个 CAS 涉及到以下操作:
我们假设内存中的原数据 V,旧的预期值 A,需要修改的新值 B。

  1. 比较 A 与 V 是否相等。(比较)
  2. 如果比较相等,将 B 写入 V。(交换)
  3. 返回操作是否成功。

CAS 伪代码:
下面写的代码不是原子的, 真实的 CAS 是一个原子的硬件指令完成的.
因为本身就是原子操作, 就没有线程安全问题,

    boolean CAS(address, expectValue, swapValue) {// 取出 address 的值if (&address == expectedValue) {&address = swapValue;return true;}return false;}

当多个线程同时对某个资源进行CAS操作,只能有一个线程操作成功,但是并不会阻塞其他线程, 其他线程只会收到操作失败的信号。

可以理解为: CAS 是乐观锁的一种实现方式

二. CAS 的应用

CAS 最大的意义: 为我们写多线程安全的代码提供新的方向和思路

1. 实现原子类

标准库中提供了 java.util.concurrent.atomic 包, 里面的类都是基于这种方式来实现的.
典型的就是 AtomicInteger 类. 其中的 getAndIncrement 相当于 i++ 操作.

AtomicInteger atomicInteger = new AtomicInteger(0);
// 相当于 i++
atomicInteger.getAndIncrement();

伪代码实现:

class AtomicInteger {private int value;public int getAndIncrement() {int oldValue = value;while ( CAS(value, oldValue, oldValue+1) != true) {// 没有成功就将期待值换为最新值oldValue = value;}return oldValue;}
}

通过形如上述代码就可以实现一个原子类. 不需要使用重量级锁, 就可以高效的完成多线程的自增操作, 技能保证线程安全又高效, 因为 加锁就涉及到锁竞争, 而 CAS 不涉及线程阻塞.

本来 check and set 这样的操作在代码角度不是原子的. 但是在硬件层面上可以让一条指令完成这个操作, 也就变成原子的了.

2. 实现自旋锁

自旋锁伪代码

public class SpinLock {private Thread owner = null;public void lock(){// 通过 CAS 看当前锁是否被某个线程持有. // 如果这个锁已经被别的线程持有, 那么就自旋等待. // 如果这个锁没有被别的线程持有, 那么就把 owner 设为当前尝试加锁的线程. while(!CAS(this.owner, null, Thread.currentThread())){}}public void unlock (){this.owner = null;}
}

三. CAS 的 ABA 问题

ABA 问题:
CAS 关键是先比较再交换, 比较实质是比较当前值和旧值是否相同, 若相同, 则视为中间没有发生改变, 就进行修改. 但是这存在漏洞, 可能中间值变化了又变回来了, CAS 就无法判断到底是否发生过改变.

假设存在两个线程 t1 和 t2. 有一个共享变量 num, 初始值为 A.
接下来, 线程 t1 想使用 CAS 把 num 值改成 Z, 那么就需要

  • 先读取 num 的值, 记录到 oldNum 变量中.
  • 使用 CAS 判定当前 num 的值是否为 A, 如果为 A, 就修改成 Z.

但是, 在 t1 执行这两个操作之间, t2 线程可能把 num 的值从 A 改成了 B, 又从 B 改成了 A

线程 t1 的 CAS 是期望 num 不变就修改. 但是 num 的值已经被 t2 给改了. 只不过又改成 A 了. 这
个时候 t1 究竟是否要更新 num 的值为 Z 呢?

t1 线程无法区分当前这个变量始终是 A, 还是经历了一个变化过程又变为 A

这就好比, 我们买一个手机, 无法判定这个手机是刚出厂的新手机, 还是别人用旧了, 又翻新过的手
机.

ABA 问题引来的 BUG:

  • 假设 A 有 100 存款. 想转账给 B 50 块钱. 但是点击转账按钮时没反应, 于是 A 又点击了一次
  • 但是取款机实际创建了两个线程, 并发的来执行 -50 操作.
  • 我们期望一个线程执行 -50 成功, 另一个线程 -50 失败.

如果使用 CAS 的方式来完成这个扣款过程就可能出现问题:

  • 正常情况,第二个 线程 CAS 期望值是 100, 但实际是 50, 所以扣款失败.
  • 但是如果转账过程中 C 又 给 A 转帐 50, 所以第二个线程 CAS 去判断余额还是 100, 所以就会扣款成功.

在这里插入图片描述

解决方案: 引入版本号

给要修改的值, 引入版本号. 在 CAS 比较数据当前值和旧值的同时, 也要比较版本号是否符合预期.

  • CAS 操作在读取旧值的同时, 也要读取版本号.

真正修改的时候,

  • 如果当前版本号和读到的版本号相同, 则修改数据, 并把版本号 + 1.
  • 如果当前版本号高于读到的版本号. 就操作失败(认为数据已经被修改过了)

在这里插入图片描述

四. 相关面试题

  1. 讲解下你自己理解的 CAS 机制
    全称 Compare and swap, 即 “比较并交换”. 相当于通过一个原子的操作, 同时完成 “读取内存, 比
    较是否相等, 修改内存” 这三个步骤. 本质上需要 CPU 指令的支撑.

  2. ABA问题怎么解决?
    给要修改的数据引入版本号. 在 CAS 比较数据当前值和旧值的同时, 也要比较版本号是否符合预期.
    如果发现当前版本号和之前读到的版本号一致, 就真正执行修改操作, 并让版本号自增; 如果发现当前版本号比之前读到的版本号大, 就操作失败.

  3. 相对于 锁机制, 为什么 CAS 效率更高?
    因为 CAS 本身就是一组原子指令, 不涉及线程安全问题, 所以不需要加锁、解锁等开销,减少了线程在互斥同步时所产生的性能消耗,当多个线程同时进行 CAS 操作时,只有一个能成功,其余则需重试,不涉及线程阻塞.

好啦! 以上就是对 CAS 的讲解,希望能帮到你 !
评论区欢迎指正 !

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

pytorch生成CAM热力图-单张图像

利用ImageNet预训练模型生成CAM热力图-单张图像 一、环境搭建二、主要代码三、结果展示 代码和图片等资源均来源于哔哩哔哩up主:同济子豪兄 讲解视频:CAM可解释性分析-算法讲解 一、环境搭建 1,安装所需的包 pip install numpy pandas mat…

干净优雅的做iOS应用内全局交互屏蔽

本文字数:4930字 预计阅读时间:28分钟 01 交互屏蔽的需求 很多应用开发者都会遇到这样一个需求,当程序需要处理某个敏感的核心任务,或者执行某些动画时,需要杜绝一切外部干扰,优先保证任务的完成&#xff0…

thinkphp:查询本周中每天中日期的数据,查询今年中每个月的数据,查询近五年每年的总数据

一、查询本周中每天中日期的数据 结果: 以今天2023-09-14为例,这一周为2023-09-11~2023-09-07 代码 后端thinkphp: //查询本周每天的的总金额数 //获取本周的起始日期和结束日期 $weekStart date(Y-m-d, strtotime(this week Monday)); $weekEnd …

centos 下 Makefile 独立模块编译ko

1、安装编译内核环境包 编译需要用到kernel 源码,centos 下需先安装 kernel-devel 包,要下与自己kernel 对应版本 yum install kernel-devel 2、首先从内核或自己写的模块,发到编译环境中 注:就像我自己拷贝一个 bcache 驱动的目…

msvcp120.dll怎么修复?msvcp120.dll丢失的解决方法

在当今这个信息化的时代,电脑已经成为我们生活和工作中不可或缺的一部分。然而,随着电脑技术的不断发展,我们也会遇到各种各样的问题。其中,msvcp120.dll丢失是一个常见的问题。一、msvcp120.dll 文件介绍 1 msvcp120.dll 文件的定…

红外成像技术

针对GI S设备红外检测目前未被大众认可的原因: 1 、 目前对GI S带电检测的意义认识不够, 许多单位认为GI S测温发现不了什么, 对其测温仅仅检测接头。 2、 GI S外壳温度异常的原因多种, 出现外壳温度异常大家不会分析,…

数据科学的文本技术 Text Technology(IR信息检索、搜索引擎)

一、文章摘要 1. 内容 * Introduction to IR and text processing, system components * Zipf, Heaps, and other text laws * Pre-processing: tokenization, normalisation, stemming, stopping. * Indexing: inverted index, boolean and proximity search * Evaluation m…

物联网行业案例 - Splashtop 助力成都谷帝科技有限公司远程维护安卓设备

成都谷帝科技有限公司专注于提供针对特定行业需求的全面物联网软硬件解决方案。其产品系列包括智慧路灯系统、智能门禁、智能柜控、智慧体育步道、农业灌溉、工业焙烧系统、水质在线检测系统等。 客户需求 成都谷帝科技有限公司提供物联网软硬件解决方案,还需要对…

伦敦银时走势与获利机会

交易时间灵活、资金杠杆充沛是伦敦银交易的主要优势,投资者应该充分利用这个品种的制度优势,结合自己个人的作息时间,在工作、投资与生活三者之间取得平衡的前提下,借助国际白银市场的波动,通过交易逐步实现自己的财富…

(21)多线程实例应用:双色球(6红+1蓝)

一、需求 1.双色球: 投注号码由6个红色球号码和1个蓝色球号码组成。 2.红色球号码从01--33中选择,红色球不能重复。 3.蓝色球号码从01--16中选择。 4.最终结果7个号码:61;即33选6(红) 16选1(蓝) 5.产品: …

深度对话|Sui在商业技术堆栈中的地位

近日,我们采访了Mysten Labs的商业产品总监Lola Oyelayo-Pearson,共同探讨了区块链技术如何为企业提供商业服务,以及为什么Sui特别适合这些用例。 1.请您简要介绍一下自己、您的角色以及您是如何开始涉足Web3领域的? 目前&#…

Docker--未完结

一.Docker是干什么的 在没亲自使用过之前,再多的术语也仅仅是抽象,只有写的人或者使用过的人能看懂。 所以,作为新手来说,只要知道Docker是用于部署项目就够了,下面展示如何用Docker部署项目及Docker常用命令。 二、…