CAS(Compare And Swap)乐观锁机制

本文深入探讨了乐观锁和悲观锁的概念,解释了synchronized作为悲观锁的工作原理,以及乐观锁通过CAS机制实现资源竞争解决的方法。同时,讨论了CAS的优缺点,包括其在高并发场景下的CPU开销问题及无法保证代码块原子性的局限。

众所周知锁有两种:乐观锁与悲观锁。

独占锁是一种悲观锁,而 synchronized 就是一种独占锁,synchronized 会导致其它所有未持有锁的线程阻塞,而等待持有锁的线程释放锁。

所谓乐观锁就是,每次不加锁而是假设没有冲突而去完成某项操作,如果因为冲突失败就重试,直到成功为止。而乐观锁用到的机制就是CAS。

什么是CAS?

CAS是英文单词Compare And Swap的缩写,翻译过来就是比较并替换。

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

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

JAVA中 java.util.concurrent.atomic包下,一系列以Atomic开头的包装类。例如AtomicBoolean,AtomicInteger,AtomicLong。它们分别用于Boolean,Integer,Long类型的原子性操作, 如下图当使用Atomic相关的类去做变量容器,就能保证变量的原子性,这样就是给变量添加了乐观锁。
在这里插入图片描述

CAS的缺点:

1.CPU开销较大

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

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

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

因为它本身就只是一个锁住总线的原子交换操作啊。两个CAS操作之间并不能保证没有重入现象。

<think>我们正在讨论CASCompare and Swap)技术,它是一种在并发编程中用于实现无锁数据结构的原子操作。根据引用内容,CAS包含三个操作数:内存位置(V)、预期原值(A)和更新值(B)。其操作逻辑是:当内存位置V的值等于预期原值A时,处理器会自动将该位置的值更新为新值B;否则,不做任何操作,并允许调用者重试(通常通过自旋循环)。 同时,引用中还提到了CAS的一些特点:无锁、乐观锁的实现、适用于竞争不激烈的场景、可能导致ABA问题、自旋消耗CPU资源等。 因此,我将按照以下结构组织回答: 1. 定义和基本操作:解释CAS是什么,并描述其三个操作数以及操作过程。 2. 原理:说明CAS如何实现无锁并发控制,并提及硬件支持(原子指令)。 3. 特点:包括优点(如避免线程阻塞、减少上下文切换)和缺点(如ABA问题、自旋消耗CPU)。 4. 应用场景:简要说明CAS在并发编程中的典型应用,例如原子类、无锁队列等。 此外,根据要求,我们需要在回答中自然地添加引用标识。由于引用[1][2][3][4][5]都提供了关于CAS的信息,我们会在相应的解释后添加引用。 最后,按照指令要求生成相关问题。 注意:所有数学表达式(如果有)需要使用$...$格式,独立公式用$$...$$。虽然CAS解释中可能不涉及复杂数学,但如果有变量表示,会使用行内数学格式。 开始回答: </think>### CASCompare and Swap)详细解释 #### 1. **基本定义与原理** CAS(比较并交换)是一种无锁并发控制技术,用于实现多线程环境下的原子操作。其核心包含三个操作数: - **内存位置(V)**:要修改的共享变量地址 - **预期原值(A)**:线程读取该内存位置时的旧值 - **更新值(B)**:希望写入的新值 **操作逻辑**: ```plaintext if V == A then V = B // 更新成功 else 重试或放弃 // 更新失败 ``` 该操作由**单条CPU指令**(如x86的`CMPXCHG`)原子性完成,确保比较和更新过程不可分割[^1][^2][^4]。 #### 2. **工作流程** 以两个线程竞争修改共享变量`V=10`为例: 1. 线程1和线程2同时读取`V=10` 2. 线程1执行`CAS(V, 10, 20)`: - 比较发现`V==10`(匹配)→ 更新`V=20`成功 3. 线程2执行`CAS(V, 10, 30)`: - 此时`V=20≠10`(不匹配)→ 更新失败 → 重新读取`V=20`并自旋重试[^1][^4] #### 3. **核心特点** | **优势** | **劣势** | |-----------------------------------|-----------------------------------| | **无锁算法**:避免线程阻塞和上下文切换开销[^3] | **ABA问题**:值从A→B→A变化时,CAS误判未修改[^3] | | **乐观锁**:假设冲突概率低,直接尝试更新[^3] | **自旋消耗CPU**:竞争激烈时循环重试浪费资源[^5] | | **原子性**:硬件级指令保证操作不可分割[^2] | **仅适用简单操作**:复杂逻辑需配合其他机制[^4] | #### 4. **典型应用场景** - **原子类实现**:如Java的`AtomicInteger`,通过CAS实现`incrementAndGet()` ```java // 伪代码实现 do { int oldValue = get(); // 读取当前值 int newValue = oldValue + 1; } while (!CAS(oldValue, newValue)); // 自旋直到成功 ``` - **无锁数据结构**:并发队列(如Disruptor RingBuffer)、并发栈[^2][^4] - **同步机制基础**:实现自旋锁、信号量等[^5] #### 5. **ABA问题解决方案** 通过添加**版本号/时间戳**扩展CAS操作: - 原始值:`A` - 扩展结构:`(A, Version=1)` - 更新时同时校验值和版本号: ```plaintext if (V.value == A && V.version == 1) then update to (B, 2) ``` 例如Java的`AtomicStampedReference`[^3][^4]。 --- ### 相关问题 1. CAS操作在哪些场景下性能优于传统锁机制? 2. 如何通过Java代码实现一个基于CAS的自旋锁? 3. ABA问题在实际系统中可能引发哪些具体风险?请举例说明 4. 对比CAS与volatile关键字在并发控制中的异同 5. 现代CPU如何通过硬件指令(如LL/SC)实现CAS的原子性?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值