当前位置: 首页 > news >正文

Java CAS - 详解

Java 中的 CAS(Compare-And-Swap)。这是一个非常重要的概念,是 Java 并发编程中无锁(Lock-Free)算法的核心。


一、什么是 CAS?

CAS 的全称是 Compare-And-Swap,即比较并交换。它是一种原子操作,用于实现多线程环境下的同步,而不需要使用重量级的锁(如 synchronized)。

它的操作过程包含三个操作数:

  1. 内存位置(V)

  2. 预期原值(A)

  3. 新值(B)

CAS 的原理:

当且仅当内存位置 V 的值等于预期原值 A 时,处理器才会将该位置的值更新为新值 B。否则,处理器不做任何操作。整个比较和交换操作是一个原子操作,执行期间不会被其他线程中断。

无论操作是否成功,它都会返回该内存位置的当前值。程序员可以根据返回的值来判断 CAS 操作是否成功。


二、在 Java 中如何实现 CAS?

Java 并没有直接提供 CAS 操作给程序员使用,而是通过 sun.misc.Unsafe 类中的一系列 compareAndSwap 本地方法(JNI)来底层实现的。

然而,我们通常不会直接使用 Unsafe 类(因为它被设计为仅供 Java 核心类库使用,是不安全的)。相反,JDK 在 java.util.concurrent.atomic 包下提供了一系列原子类(如 AtomicIntegerAtomicLongAtomicReference 等),这些类为我们封装了 CAS 操作,提供了简单易用的 API。

一个经典的例子:使用 AtomicInteger

import java.util.concurrent.atomic.AtomicInteger;public class CASDemo {public static void main(String[] args) {AtomicInteger atomicInt = new AtomicInteger(5); // 初始值为 5// 尝试进行 CAS 操作// 参数1:expect - 期望当前值是多少// 参数2:update - 如果期望值正确,要设置的新值是多少boolean success1 = atomicInt.compareAndSet(5, 10); // 当前值是5,匹配期望值5,所以更新为10,返回trueSystem.out.println("CAS操作1是否成功: " + success1 + ", 当前值: " + atomicInt.get());boolean success2 = atomicInt.compareAndSet(5, 15); // 当前值是10,不等于期望值5,所以更新失败,返回falseSystem.out.println("CAS操作2是否成功: " + success2 + ", 当前值: " + atomicInt.get()); // 值仍然是10}
}

输出:

CAS操作1是否成功: true, 当前值: 10
CAS操作2是否成功: false, 当前值: 10

compareAndSet 方法就是最典型的 CAS 操作在 Java 中的体现。


三、CAS 的底层原理

CAS 的原子性实际上是由硬件(主要是 CPU)来保障的。大部分现代处理器(如 x86)都提供了实现 CAS 操作的指令(例如 CMPXCHG 指令)。

Java 通过 JNI(Java Native Interface)调用这些由 C++ 实现的本地方法,这些本地方法再调用 CPU 的原子指令来完成操作。这个过程大致如下:

  1. Java 代码:调用 AtomicInteger.compareAndSet()

  2. JVM: JVM 会将其转换为对 Unsafe.compareAndSwapInt() 方法的调用。

  3. 本地方法: Unsafe.compareAndSwapInt() 是一个 native 方法,它通过 JNI 进入 JVM 的本地代码(C++)实现。

  4. 汇编指令: 在本地代码中,会根据当前操作系统和 CPU 架构,调用对应的底层原子指令(如 lock cmpxchg)。

  5. CPU 执行: CPU 原子性地执行比较和交换操作,并返回结果。

关键点: lock 前缀指令在多核处理器下确保了对内存操作的独占性。它会锁定一个小的内存区域或者总线,防止其他 CPU 在该指令执行期间访问该内存,从而保证了原子性。


四、CAS 的典型应用场景

  1. 原子类: java.util.concurrent.atomic 包下的所有类,其自增、自减、累加等操作都是基于 CAS 实现的。

    AtomicInteger i = new AtomicInteger(0);
    i.incrementAndGet(); // 底层使用 CAS 循环实现,线程安全
  2. 并发容器: 如 ConcurrentHashMap,在 JDK 1.8 后的实现中,大量使用了 CAS 来优化同步性能,比如在 putVal 方法中初始化数组桶、插入链表头节点等。

  3. 锁机制: 许多显式锁(如 ReentrantLock)和同步工具(如 AQS AbstractQueuedSynchronizer)的内部实现中,对状态的修改也大量使用了 CAS 来避免直接的锁竞争。


五、CAS 的优缺点

优点:
  • 性能高: 它是一种乐观锁,在竞争不激烈的情况下,性能远高于传统的同步锁(如 synchronized),因为它避免了线程阻塞和上下文切换的开销。

  • 避免死锁: 由于是无锁操作,从根本上避免了死锁问题。

缺点:
  1. ABA 问题

    • 描述: 假设一个变量初始值为 A。线程1准备将其改为 C,于是先读取到值为 A。在此期间,线程2将值改为了 B,然后又改回了 A。这时线程1执行 CAS 操作,发现值还是 A,于是成功更新为 C。但这个过程对于线程1来说是感知不到中间状态 B 的,这就像什么都没发生一样,但在某些业务场景下这可能是个问题(例如一个链表的头节点被修改又改回,其内部状态可能已变化)。

    • 解决方案: JDK 提供了 AtomicStampedReference 和 AtomicMarkableReference 类,它们通过一个版本号(Stamp)或标记来避免 ABA 问题。每次修改版本号都会增加,CAS 操作同时比较值和版本号。

  2. 循环时间长开销大

    • 描述: 如果 CAS 操作长时间不成功(比如竞争非常激烈),CPU 会一直进行循环尝试,会给 CPU 带来很大的开销。

    • 解决方案: 通常可以限制自旋次数,或者与更高级的锁机制结合使用。

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

    • 描述: 一个 CAS 操作只能针对一个变量。

    • 解决方案: 如果需要同时对多个变量进行原子操作,可以将多个变量封装成一个对象,然后使用 AtomicReference 来保证原子性。JDK 也提供了 AtomicReferenceFieldUpdater 等工具。


总结

特性描述
本质一种硬件支持的原子操作指令(Compare-And-Swap)。
Java 体现通过 java.util.concurrent.atomic 包下的原子类(如 AtomicInteger)的 compareAndSet() 等方法暴露给开发者。
核心思想乐观锁:先尝试修改,如果失败(发生冲突)就重试,而不是直接加锁。
优点高性能(无阻塞,无上下文切换),避免死锁
缺点ABA 问题(可通过版本号解决)、循环开销只能操作一个变量

CAS 是构建高效、高并发 Java 应用程序的基石之一,理解它对于深入掌握 Java 并发编程至关重要。


文章转载自:

http://c3Ur7rF0.ktcfL.cn
http://RcE4bGaZ.ktcfL.cn
http://X3dxIEd8.ktcfL.cn
http://YXHJaZUV.ktcfL.cn
http://oeWII6EN.ktcfL.cn
http://EMMjFmF7.ktcfL.cn
http://XhQEuILc.ktcfL.cn
http://Evi8RShB.ktcfL.cn
http://S7yXNwJ5.ktcfL.cn
http://rUJmRz7E.ktcfL.cn
http://EACPUDvR.ktcfL.cn
http://nITRrN1d.ktcfL.cn
http://4yHcsfGn.ktcfL.cn
http://qBsb0iu0.ktcfL.cn
http://PFlNNG5I.ktcfL.cn
http://qtSFF5BV.ktcfL.cn
http://rLZxzzZj.ktcfL.cn
http://9q36dEtT.ktcfL.cn
http://t4HBxwu1.ktcfL.cn
http://nVJjm9Tm.ktcfL.cn
http://q4Z6xmJM.ktcfL.cn
http://uCTcnT2u.ktcfL.cn
http://8qzlciTB.ktcfL.cn
http://RiynJSpW.ktcfL.cn
http://zwwYYLtM.ktcfL.cn
http://7TaeWjqp.ktcfL.cn
http://w2ujwI0F.ktcfL.cn
http://RRUtBqZQ.ktcfL.cn
http://Th3yhxRz.ktcfL.cn
http://v0f6qOrG.ktcfL.cn
http://www.dtcms.com/a/369513.html

相关文章:

  • 生态 | 华院计算与深至科技达成战略合作,携手推动AI+医学影像算法升级迭代
  • 力扣416:分割等和子集
  • ATGM336H-5N数据解析说明
  • 2025高中文凭能考的证书大全
  • Windows Server2012 R2 安装.NET Framework 3.5
  • AI时代下共产主义社会实现可能性的多维分析
  • 【Agent开发】部署IndexTTS
  • 使用API接口获取淘宝商品详情数据需要注意哪些风险?
  • 消费品企业客户数据分散?CRM 系统来整合
  • STM32项目分享:面向复杂路段的可控智能交通信号灯设计
  • 【完整源码+数据集+部署教程】加工操作安全手套与手部检测系统源码和数据集:改进yolo11-cls
  • 当洗地机开始「懂你」:VTX316如何让科技更有温度
  • 深度学习模型在边缘计算设备上的部署
  • 【C++题解】贪心和模拟
  • 小学生学习机如何选?AI英语与护眼是关键
  • centos 系统如何安装open jdk 8
  • Git 工具的「安装」及「基础命令使用」
  • PCB 残胶怎么除?猎板分享高效且安全的去除工艺方案
  • 基于FPGA实现数字QAM调制系统
  • 【代码随想录算法训练营——Day2】链表——203.移除链表元素、707.设计链表、206.反转链表
  • GEO公司有哪些:AI时代品牌可见性策略全景分析
  • 迁移学习的案例
  • Linux 入门到精通,真的不用背命令!零基础小白靠「场景化学习法」,3 个月拿下运维 offer,第二十七天
  • 极快文本嵌入推理:Rust构建高性能嵌入推理解决方案
  • 2025国赛C题创新论文+代码可视化 NIPT 的时点选择与胎儿的异常判定
  • MySQL高级进阶(流程控制、循环语句、触发器)
  • JavaScript 源码剖析:从字节码到执行的奇妙旅程
  • 内存纠错检错方法-SSCDSD
  • PostgreSQL收集pg_stat_activity记录的shell工具pg_collect_pgsa
  • AI助力决策:告别生活与工作中的纠结,明析抉择引领明智选择