什么是CAS?

CAS

原理

无锁编程:Lock Free

CAS 的全称是 Compare-And-Swap,是 CPU 并发原语.

必须是原子操作。 CAS 的底层是 lock cmpxchg 指令(X86 架构),在单核 CPU 和多核 CPU 下都能够保证【比较-交换】的原子性。

-----【底层是操作系统层面的锁】

-----【CAS 必须借助 volatile 才能读取到共享变量的最新值来实现【比较并交换】的效果】

 

  • CAS 并发原语体现在 Java 语言中就是 sun.misc.Unsafe 类的各个方法,调用 UnSafe 类中的 CAS 方法,JVM 会实现出 CAS 汇编指令,这是一种完全依赖于硬件的功能,实现了原子操作

  • CAS 是一种系统原语,原语属于操作系统范畴,是由若干条指令组成 ,用于完成某个功能的一个过程,并且原语的执行必须是连续的,执行过程中不允许被中断,所以 CAS 是一条 CPU 的原子指令不会造成数据不一致的问题是线程安全的

底层原理:CAS 的底层是 lock cmpxchg 指令(X86 架构),在单核和多核 CPU 下都能够保证比较交换的原子性

  • 程序是在单核处理器上运行,会省略 lock 前缀,单处理器自身会维护处理器内的顺序一致性,不需要 lock 前缀的内存屏障效果

  • 程序是在多核处理器上运行,会为 cmpxchg 指令加上 lock 前缀。当某个核执行到带 lock 的指令时,CPU 会执行总线锁定或缓存锁定,将修改的变量写入到主存,这个过程不会被线程的调度机制所打断,保证了多个线程对内存操作的原子性

作用:比较当前工作内存中的值和主物理内存中的值,如果相同则执行规定操作,否则继续比较直到主内存和工作内存的值一致为止

CAS 特点:

  • CAS 体现的是无锁并发、无阻塞并发,线程不会陷入阻塞(一直运行),线程不需要频繁切换状态(上下文切换,系统调用)

  • CAS 是基于乐观锁的思想

CAS 缺点:

  • 执行的是循环操作,如果比较不成功一直在循环,最差的情况某个线程一直取到的值和预期值都不一样,就会无限循环导致饥饿,使用 CAS 线程数不要超过 CPU 的核心数,采用分段 CAS 和自动迁移机制 【如果没有分到时间片,仍然会进入可运行状态,还是会导致上下文切换。】

  • 只能保证一个共享变量的原子操作

    • 对于一个共享变量执行操作时,可以通过循环 CAS 的方式来保证原子操作

    • 对于多个共享变量操作时,循环 CAS 就无法保证操作的原子性,这个时候只能用锁来保证原子性

  • 引出来 ABA 问题。即A变成B,B又变成A,无法察觉他被修改过,但一般业务都不被这个影响。


乐观锁

CAS 与 synchronized 总结:

  • synchronized 是从悲观的角度出发:总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞(共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程),因此 synchronized 也称之为悲观锁,ReentrantLock 也是一种悲观锁,性能较差

  • CAS 是从乐观的角度出发:总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据。如果别人修改过,则获取现在最新的值,如果别人没修改过,直接修改共享数据的值,CAS 这种机制也称之为乐观锁,综合性能较好

<think>我们正在讨论Java中的CAS(Compare-And-Swap)概念及其原理。根据用户的问题,我们需要解释CAS是什么以及它的工作原理。同时,我们参考了提供的引用内容,这些引用主要涉及CASJava中的实现,包括Unsafe类、底层CPU指令以及CAS的优缺点等。 CAS是一种无锁的并发编程技术,它通过硬件指令保证操作的原子性。在Java中,CAS操作通常通过sun.misc.Unsafe类中的本地方法实现,这些方法会编译成特定的CPU指令(如x86架构的cmpxchg指令)。 下面我们将按照以下结构回答: 1. CAS的定义 2. CAS的工作原理(包括底层原理) 3. CASJava中的具体实现(以AtomicInteger为例) 4. CAS的优缺点 5. 相关问题生成 注意:在回答中,我们会适当引用提供的参考文献,并在引用处标注引用标识。</think>### Java 中的 CAS 概念及原理详解 **CAS(Compare-And-Swap)** 是一种无锁并发编程的核心技术,通过硬件指令保证原子性操作。其本质是:**比较内存值是否与预期值相同,若相同则更新为新值,否则放弃操作**。 --- #### 一、CAS 是什么? 1. **定义**: - CAS 是 **原子操作**,由 CPU 提供底层支持(如 x86 的 `cmpxchg` 指令)[^3]。 - Java 通过 `sun.misc.Unsafe` 类封装这些指令(用户不可直接调用,需通过原子类如 `AtomicInteger` 使用)[^1][^2]。 2. **核心思想**: - 通过 **自旋(循环尝试)** 实现无锁同步,避免线程阻塞[^2]。 - 解决并发问题的公式: $$ \text{CAS}(V, E, N) = \begin{cases} \text{更新 } V \text{ 为 } N & \text{if } V = E \\ \text{放弃操作} & \text{otherwise} \end{cases} $$ 其中: - $V$:内存中的当前值 - $E$:预期值(Expected) - $N$:新值(New) --- #### 二、CAS 工作原理 ##### 底层实现流程: 1. **读取内存值**: 线程从共享内存中读取当前值 $V$。 2. **计算新值**: 基于业务逻辑生成新值 $N$(如 `AtomicInteger` 的 `incrementAndGet()` 会将 $V+1$)。 3. **执行 CAS 指令**: - CPU 执行原子指令(如 `cmpxchg`),**比较内存值 $V$ 是否等于预期值 $E$**(即步骤 1 读取的值)[^3]。 - 若相等:将内存值更新为 $N$,返回成功。 - 若不相等:放弃操作,返回失败。 4. **自旋重试**: 若失败,线程重新执行步骤 1-3(循环直到成功或超时)[^2]。 ##### Java 中的实现(以 `AtomicInteger` 为例): ```java // AtomicInteger.getAndIncrement() 源码 public final int getAndIncrement() { return unsafe.getAndAddInt(this, valueOffset, 1); // 调用 Unsafe 类 } // Unsafe.getAndAddInt() 核心逻辑 public final int getAndAddInt(Object o, long offset, int delta) { int v; do { v = getIntVolatile(o, offset); // 读取内存值 V } while (!compareAndSwapInt(o, offset, v, v + delta)); // 自旋 CAS return v; } ``` - **`compareAndSwapInt`**: - 底层通过 JNI 调用 CPU 的原子指令[^1][^3]。 - 若内存值等于 $v$(预期值),则将其更新为 $v + \text{delta}$(新值)。 --- #### 三、为什么使用 CAS? 1. **对比 `synchronized`**: | **特性** | **CAS** | **synchronized** | |----------------|-----------------------------|--------------------------| | **锁机制** | 无锁(自旋) | 悲观锁(阻塞线程) | | **性能** | 高(无上下文切换)[^2] | 低(线程切换开销大) | | **适用场景** | 低竞争、简单操作 | 高竞争、复杂临界区 | 2. **优势**: - **避免死锁**:无锁机制天然免疫死锁。 - **高吞吐量**:轻量级操作,适合计数器等场景[^3]。 --- #### 四、CAS 的缺陷 1. **ABA 问题**: - **场景**:线程 A 读取值 $X$,线程 B 将 $X→Y→X$,线程 A 的 CAS 仍成功(未感知中间变化)。 - **解决方案**: - 使用 **版本号标记**(如 `AtomicStampedReference`)。 $$ \text{内存值} = (\text{value}, \text{stamp}) \quad \text{预期值} = (\text{expectedValue}, \text{expectedStamp}) $$ 2. **自旋开销**: - 高竞争场景下,长时间自旋消耗 CPU 资源[^2]。 3. **单变量限制**: - 只能保证**单个共享变量**的原子性,多个变量需额外同步。 --- ### 总结 - **CAS 本质**:硬件支持的原子指令,通过 **比较-更新** 实现无锁同步。 - **Java 实现**:由 `Unsafe` 类封装 CPU 指令,原子类(如 `AtomicInteger`)提供用户接口[^1][^3]。 - **适用场景**:计数器、状态标志等低竞争简单操作。 - **规避缺陷**:ABA 问题需添加版本号,高竞争场景改用锁机制。 > **设计哲学**:CAS 是乐观锁的基石,通过“重试”而非“阻塞”平衡性能与安全性。 --- ### 相关问题 1. **ABA 问题如何影响业务逻辑?** 举例说明并给出代码解决方案[^2]。 2. **CASJava 并发包中的具体应用有哪些?**(如 `ConcurrentHashMap` 的分段锁实现) 3. **自旋锁与阻塞锁的性能对比实验设计**:如何量化测试不同竞争强度下的吞吐量? 4. **除了 CAS,还有哪些无锁并发技术?**(如 RCU、Seqlock) [^1]: JavaCAS 操作通过 `Unsafe` 类对接 CPU 指令 [^2]: CAS 通过自旋实现无锁同步,但存在 ABA 问题 [^3]: CAS 的底层依赖 CPU 原子指令(如 x86 的 `cmpxchg`)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值