👉博主介绍: 博主从事应用安全和大数据领域,有8年研发经验,5年面试官经验,Java技术专家,WEB架构师,阿里云专家博主,华为云云享专家,51CTO 专家博主
⛪️ 个人社区:个人社区
💞 个人主页:个人主页
🙉 专栏地址: ✅ Java 中级
🙉八股文专题:剑指大厂,手撕 Java 八股文
1. 什么是 CAS
CAS 是“Compare and Swap”的缩写,指的是一种并发编程技术。CAS 是一种乐观锁技术,用于实现多线程环境下的原子操作。CAS 操作包括三个步骤:比较内存中的值与预期值、如果相等则更新为新值、否则重试。在 Java 中,java.util.concurrent 包中的 Atomic 类和 AtomicReference 类提供了 CAS 操作的实现,例如 AtomicLong、AtomicInteger 等。CAS 可以用于实现非阻塞算法,提高并发性能。
2. ABA问题
ABA 问题是在并发编程中常见的一种问题,指的是在使用 CAS(Compare and Swap)等乐观锁技术时可能发生的情况。ABA 问题的具体情况是:线程 A 读取共享变量的值为 A,然后线程 B 将共享变量的值从 A 修改为 B,最后又改回 A,此时线程 A 再次读取共享变量的值为 A,看起来就好像共享变量的值没有发生变化。这种情况可能导致程序逻辑错误或数据不一致。
为了解决 ABA 问题,可以使用版本号或标记等方式来标记共享变量的变化,确保在进行 CAS 操作时同时检查版本号或标记,从而避免出现 ABA 问题。Java 中的 AtomicStampedReference 类就是为了解决 ABA 问题而设计的,它在 CAS 操作中不仅比较值,还比较版本号,从而提供了更安全的并发操作。
3. 什么是忙等待
忙等待(Busy Waiting)是一种在计算机编程中常见的技术,用于实现并发控制或同步。在忙等待中,线程或进程会反复检查某个条件是否满足,如果条件未满足,则会不断循环等待,直到条件满足才继续执行后续操作。忙等待通常使用在轮询式的同步机制中,例如在实现自旋锁、CAS 等操作时。
忙等待的优点是简单直接,避免了线程切换和上下文切换带来的开销,适用于一些短暂等待时间的场景。然而,忙等待会占用处理器资源,降低系统的效率,而且在长时间等待的情况下可能会引发性能问题。因此,在实际应用中需要根据具体情况选择合适的同步机制,避免过度使用忙等待。
4. CAS 的实现原理
CAS(Compare and Swap)是一种并发编程中常用的原子操作,用于实现多线程环境下的同步和原子性操作。CAS 操作包括三个步骤:
- 比较:首先,CAS 会读取内存中的值和预期值进行比较。
- 交换:如果内存中的值和预期值相等,CAS 就会将内存中的值替换为新值。
- 返回结果:CAS 操作返回一个布尔值,表示操作是否成功。
CAS 的实现原理通常依赖底层硬件的支持,例如处理器提供的原子指令(比如 x86 架构的 CMPXCHG 指令)。在 Java 中,CAS 操作由 Unsafe 类或 java.util.concurrent.atomic 包中的原子类(如 AtomicLong、AtomicInteger)提供支持。
CAS 的实现原理基于乐观锁思想,通过比较并交换的方式实现原子性操作,避免了传统锁机制的性能开销。然而,CAS 也可能存在ABA问题,因此在一些情况下需要结合版本号或标记来解决。
5. CAS 的应用场景
CAS(Compare and Swap)常用于并发编程中,适用于需要实现原子操作和同步的场景。以下是一些 CAS 的应用场景:
- 实现自旋锁:CAS 可以用于实现自旋锁,避免了线程阻塞和上下文切换的开销,提高了并发性能。
- 线程安全的计数器:CAS 可以用于实现线程安全的计数器,确保多线程下的计数操作是原子的。
- 无锁数据结构:CAS 可以用于实现无锁的数据结构,如非阻塞队列、无锁栈等,提高并发性能。
- 原子操作:CAS 可以用于实现原子操作,如原子更新变量、原子更新引用等。
- 实现乐观锁:CAS 可以用于实现乐观锁机制,通过比较和交换来确保数据的一致性。
6. CAS 的代码案例
import java.util.concurrent.atomic.AtomicInteger; public class CASExample {
private static AtomicInteger count = new AtomicInteger(0); public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
int expectedValue = count.get(); int newValue = expectedValue + 1; while (!count.compareAndSet(expectedValue, newValue)) {
expectedValue = count.get(); newValue = expectedValue + 1; } System.out.println("Thread 1: Incremented count to " + newValue); }); Thread thread2 = new Thread(() -> {
int expectedValue = count.get(); int newValue = expectedValue + 1; while (!count.compareAndSet(expectedValue, newValue)) {
expectedValue = count.get(); newValue = expectedValue + 1; } System.out.println("Thread 2: Incremented count to " + newValue); }); thread1.start(); thread2.start(); try {
thread1.join(); thread2.join(); } catch (InterruptedException e) {
e.printStackTrace(); } System.out.println("Final count value: " + count.get()); } }
上面使用了 AtomicInterger 类来实现一个原子计数器。两个线程分别尝试递增计数器的值,通过 compareAndSet 方法来实现 CAS 操作,确保原子性。最终输出计数器的最终值。
今天的文章 你知道什么是 CAS 吗?分享到此就结束了,感谢您的阅读。精彩专栏推荐订阅:在下方专栏👇🏻
✅ 2023年华为OD机试真题(A卷&B卷)+ 面试指导
✅ 精选100套 Java 项目案例
✅ 面试需要避开的坑(活动)
✅ 你找不到的核心代码
✅ 带你手撕 Spring
✅ Java 初阶
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/bian-cheng-ji-chu/81088.html