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

Java的CAS机制:无锁并发控制及其高频面试题

一、什么是CAS?

CAS(Compare-And-Swap,比较并交换)是一种无锁的原子操作,用于实现多线程同步。它是现代CPU通过硬件支持的原子指令,也是许多并发工具类的底层实现原理。

CAS 操作包含三个操作数:

  • 内存位置(V)​
  • 预期原值(A)​
  • 新值(B)​

基本逻辑是:​

如果内存位置 V 的值与预期原值 A 相匹配,那么就将该位置的值更新为新值 B;否则,不修改该值。无论哪种情况,都会返回该内存位置当前的值。

这个操作是原子性的,即执行期间不会被其他线程打断。


二、Java中的CAS实现

在 Java 中,CAS 操作主要通过 java.util.concurrent.atomic包下的原子类实现,比如:

  • AtomicInteger
  • AtomicLong
  • AtomicBoolean
  • AtomicReference

这些类底层使用 ​Unsafe 类​ 调用了 CPU 提供的 CAS 指令(如 x86 架构下的 CMPXCHG指令)。

示例:AtomicInteger 中的 CAS

AtomicInteger atomicInteger = new AtomicInteger(0);// 模拟 CAS 操作:如果当前值是 0,就设置为 1
boolean success = atomicInteger.compareAndSet(0, 1);
  • compareAndSet(expect, update)方法就是 CAS 的体现
  • 它会检查当前值是否等于 expect,如果是,则更新为 update,并返回 true;否则不更新,返回 false

三、CAS 的工作原理与特点

特点:

  1. 乐观锁策略​:假设并发冲突不常发生,先尝试更新,如果不成功则重试或不处理
  2. 无锁(Lock-Free)​​:不使用传统 synchronized 或 Lock,避免了线程阻塞和上下文切换
  3. 原子性​:CAS 操作本身是原子的,由硬件保证
  4. 自旋(Spin)​​:当 CAS 失败时,通常会采用自旋(循环重试)的方式,直到成功

缺点:

  1. ABA 问题​:一个值从 A 变成 B 又变回 A,CAS 会认为没有变化,但实际上已经变更过
  2. 自旋开销​:在高并发场景下,如果 CAS 长时间不成功,会导致大量 CPU 空转
  3. 只能保证一个变量的原子操作​:无法直接用于多个变量的原子更新

四、CAS 的常见应用

1. 原子类

AtomicInteger counter = new AtomicInteger(0);// 线程安全的自增
counter.incrementAndGet(); // 内部使用 CAS

2. 实现非阻塞算法

比如实现一个简单的非阻塞栈或队列,利用 CAS 来更新头尾节点。

3. AQS(AbstractQueuedSynchronizer)

Java 中很多同步工具如 ReentrantLock、CountDownLatch、Semaphore 的底层都依赖 AQS,而 AQS 的核心部分就使用了 CAS 来控制线程的排队与唤醒。


五、CAS 高频面试题

1. 什么是 CAS?它的底层原理是什么?

CAS(Compare-And-Swap)是比较并交换的缩写,是一种无锁的原子操作,用于实现多线程同步。它包含三个操作数:内存地址 V、预期原值 A 和新值 B。当且仅当 V 的值等于 A 时,才将 V 的值更新为 B,否则不修改值。整个操作是原子的,由 CPU 硬件指令保证。

在 Java 中,CAS 通过 Unsafe类调用本地方法,最终由 CPU 的原子指令(如 x86 的 CMPXCHG)实现。


2. Java 中哪些类使用了 CAS?

Java 中的 java.util.concurrent.atomic包下的原子类,如:

  • AtomicInteger
  • AtomicLong
  • AtomicBoolean
  • AtomicReference
  • 以及它们的数组版本,如 AtomicIntegerArray

此外,JUC 中的许多同步工具(如 ReentrantLock、CountDownLatch、Semaphore)的底层实现也依赖 CAS。


3. CAS 和 synchronized 有什么区别?各自优缺点是什么?

对比维度

CAS

synchronized

实现机制

无锁,基于硬件原子指令

有锁,基于监视器锁(Monitor)

阻塞性

非阻塞,线程不会挂起

阻塞,未获取锁的线程会被挂起

线程状态

不会进入阻塞态,一直处于就绪或运行

可能进入 BLOCKED 或 WAITING 状态

性能

高并发下可能自旋消耗 CPU

高并发下线程切换开销大

适用场景

低冲突、简单原子操作

复杂同步逻辑、临界区较大

CAS 优点:​​ 无锁、并发性能高、避免线程上下文切换

CAS 缺点:​​ ABA 问题、自旋可能浪费 CPU、只能保证单个变量的原子性


4. 什么是 CAS 的 ABA 问题?如何解决?

ABA 问题:​

线程 1 读取内存值为 A,准备将其更新为 B;但在它执行 CAS 之前,线程 2 将值从 A 改为 B,又改回 A。此时线程 1 执行 CAS,发现当前值仍是 A,于是更新成功,但实际上中间已经发生过变更。

解决方法:​

使用 ​带版本号的原子引用类,如 AtomicStampedReferenceAtomicMarkableReference,在比较值的同时也检查版本号或标记位,从而识别出值是否被更改过。

示例:

AtomicStampedReference<Integer> ref = new AtomicStampedReference<>(100, 0);// 更新时同时检查值和版本号
int stamp = ref.getStamp();
ref.compareAndSet(100, 101, stamp, stamp + 1);

5. CAS 自旋(循环重试)会导致什么问题?如何优化?

问题:​

当多个线程同时尝试修改同一个变量,只有一个线程会成功,其他线程 CAS 失败后会不断自旋重试,如果并发很高或冲突严重,会导致大量 CPU 空转,浪费资源。

优化方式:​

  1. 限制自旋次数,超过阈值后可以放弃或转为阻塞
  2. 退避策略,如随机等待一段时间再重试
  3. 结合锁使用,在竞争激烈时降级为锁机制
  4. 减少热点变量的竞争,优化数据结构和算法

6. 为什么说 CAS 是乐观锁?

因为 CAS ​假设并发冲突不常发生,采取“先尝试更新,失败再处理”的策略,而不是像悲观锁那样“先加锁,再操作”。它不阻止其他线程的并发访问,而是通过原子操作和重试机制来保证正确性,因此属于乐观锁的一种实现方式


7. CAS 能否保证多个变量的原子操作?

不能直接保证。​

CAS 只能针对单个变量的原子更新。如果需要保证多个变量更新的原子性,可以采用以下方式:

  • 使用一个对象封装多个变量,然后对该对象的引用进行 CAS(如 AtomicReference
  • 使用锁(synchronized 或 Lock)
  • 使用 AtomicReference结合自定义对象

六、总结

CAS 是 Java 并发编程中非常重要的基础技术,是实现高性能无锁算法和并发容器的核心。它在 Atomic类、AQS、并发工具类中都有广泛应用。

优点:​​ 无锁、高并发性能好、避免线程阻塞

缺点:​​ 存在 ABA 问题、自旋可能浪费 CPU、只能保证单一变量原子性

http://www.dtcms.com/a/356461.html

相关文章:

  • OpenCSG月度更新2025.8
  • 1 分钟 Maya 动画渲染要多久?5 天还是 5 小时
  • 基于Java、GeoTools与PostGIS的GeoJSON动态属性注入实战指南
  • 在 Go 项目的 DDD 分层架构中,Echo Web 框架及其 middleware 应该归属到哪一层?
  • mysql安全运维之安全模型与原则-构建坚不可摧的数据库防护体系
  • 自然语言提取PDF表格数据
  • 电影交流|基于SprinBoot+vue的电影交流平台小程序系统(源码+数据库+文档)
  • 在基于 Go 的 DDD 分层架构中,包含多个server的项目目录结构应如何组织?
  • LoraConfig target modules加入embed_tokens(64)
  • 设计模式-行为型模式-命令模式
  • Spring 微服务架构下的单元测试优化实践:从本地连接到真实开发数据库的集成测试
  • Qt节点编辑器设计与实现:动态编辑与任务流可视化(一)
  • WebStorm-在WebStorm中使用Git管理项目
  • 【WPF】WPF 自定义控件实战:从零打造一个可复用的 StatusIconTextButton (含避坑指南)
  • 循环高级(2)
  • 面试八股文之——JVM与并发编程/多线程
  • Azure、RDP、NTLM 均现高危漏洞,微软发布2025年8月安全更新
  • 【物联网】什么是 DHT11(数字温湿度传感器)?
  • C++ 编译和运行 LibCurl 动态库和静态库
  • SyncBack 备份同步软件: 使用 FTPS、SFTP 和 HTTPS 安全加密传输文件
  • 【2025 完美解决】Failed connect to github.com:443; Connection timed out
  • 网络编程(2)—多客户端交互
  • 跨境物流新引擎:亚马逊AGL空运服务赋能卖家全链路升级
  • Pycharm 登录 Github 失败
  • idea2023.3遇到了Lombok失效问题,注释optional和annotationProcessorPaths即可恢复正常
  • “FAQ + AI”智能助手全栈实现方案
  • 极飞科技AI智慧农业实践:3000亩棉田2人管理+产量提15%,精准灌溉与老农操作门槛引讨论
  • autojs RSA加密(使用public.pem、private.pem)
  • 【拍摄学习记录】03-曝光
  • Lora与QLora