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

深入剖析CAS:无锁并发编程的核心机制与实际应用

1. 什么是CAS(Compare-And-Swap)?

CAS(Compare-And-Swap,比较并交换)是现代并发编程中的一种无锁机制,广泛用于实现多线程的安全操作。CAS的基本原理是通过比较当前值与预期值是否一致,来决定是否更新内存中的值。

CAS通过硬件支持,在处理器层面提供原子操作,因此避免了传统锁的开销。它是Java中无锁算法(如java.util.concurrent包中的Atomic类)实现的基础。

CAS的核心操作有三个:
  • 当前值:操作数在内存中的现值。
  • 预期值:期望操作数的值。
  • 新值:需要将现值更新为的新值。

操作过程:

  • 如果当前值与预期值相同,则将当前值替换为新值;
  • 如果不同,则操作失败,需要重新尝试。

2. CAS的问题

虽然CAS能有效避免锁竞争,但是它也有几个潜在问题:

  1. ABA问题:假设一个值从A变成B,再变回A,CAS无法检测到中间的变化。此时CAS判断值没有变化,从而错误地认为更新成功。
  2. 自旋消耗CPU:CAS操作在失败时会不断重试,这种自旋操作会带来较大的CPU消耗,尤其是在并发竞争激烈时。
  3. 只能处理一个变量:CAS只能保证对单个变量的原子性操作,无法处理多个变量的原子操作。

3. Java模拟代码:CAS操作

我们通过Java的AtomicInteger类模拟CAS操作,该类底层依赖CAS来保证线程安全。以下代码展示了CAS机制的工作原理:

import java.util.concurrent.atomic.AtomicInteger;

public class CASExample {
    public static void main(String[] args) {
        AtomicInteger atomicInteger = new AtomicInteger(100);

        // 模拟多个线程竞争修改同一个值
        for (int i = 0; i < 3; i++) {
            new Thread(() -> {
                int expectedValue = atomicInteger.get(); // 预期值
                int newValue = expectedValue + 50; // 新值

                boolean isUpdated = atomicInteger.compareAndSet(expectedValue, newValue);
                if (isUpdated) {
                    System.out.println(Thread.currentThread().getName() + " 成功更新值:" + expectedValue + " -> " + newValue);
                } else {
                    System.out.println(Thread.currentThread().getName() + " 更新失败,当前值:" + atomicInteger.get());
                }
            }).start();
        }
    }
}

4. 代码详细解释

  1. AtomicIntegerAtomicInteger使用CAS操作来保证在多线程环境下对整数值的原子操作。

  2. compareAndSet:调用compareAndSet方法,CAS首先比较当前值与预期值是否一致,如果一致则更新为新值。如果在其他线程中该值已经被修改,更新失败,返回false

  3. 线程模拟竞争:我们启动了三个线程,模拟多个线程同时尝试修改同一个值的情况。每个线程先读取当前值,然后将其加50后尝试更新。只有第一个获取到预期值的线程能够成功更新,其他线程会因为值已经被修改而更新失败。

5. 运行结果

可能的输出如下(实际顺序取决于线程调度):

Thread-0 成功更新值:100 -> 150
Thread-2 更新失败,当前值:150
Thread-1 更新失败,当前值:150

从输出可以看到,只有一个线程成功更新了值,而其他线程由于预期值与实际值不一致,导致更新失败。

6. 使用场景及解决的问题

使用场景:
  1. 无锁算法:在高并发场景下,传统的锁机制容易导致线程阻塞,而CAS可以避免这种问题,适合用于实现无锁数据结构,如AtomicIntegerConcurrentLinkedQueue等。
  2. 高效计数器:CAS常用于实现高效的计数器,特别是在Atomic系列类中,如AtomicIntegerAtomicLong
  3. 并发数据结构:例如ConcurrentHashMap使用了CAS来保证线程安全的同时,提升了并发性能。
解决的问题:
  1. 高并发下的锁竞争:CAS通过硬件原子操作,可以避免线程之间的竞争和上下文切换,提升并发性能。
  2. 轻量级同步:相比传统的锁,CAS更轻量,不会导致线程阻塞,因此适合那些需要频繁更新共享资源但又不希望引入锁开销的场景。

7. 业务场景中的借用与应用

场景示例:高并发环境下的库存扣减

在电商场景下,秒杀活动或大促销时,库存的扣减是一个非常高频的操作。使用传统的锁机制可能会导致大量线程竞争锁,降低系统吞吐量。此时,我们可以借助CAS机制实现无锁的库存扣减。

以下代码演示了如何在高并发环境下使用CAS进行库存扣减操作:

import java.util.concurrent.atomic.AtomicInteger;

public class Inventory {
    private AtomicInteger stock;

    public Inventory(int initialStock) {
        this.stock = new AtomicInteger(initialStock);
    }

    public boolean reduceStock(int amount) {
        while (true) {
            int currentStock = stock.get();
            if (currentStock < amount) {
                System.out.println("库存不足,无法扣减");
                return false;
            }

            int newStock = currentStock - amount;
            if (stock.compareAndSet(currentStock, newStock)) {
                System.out.println("成功扣减库存:" + amount + ",剩余库存:" + newStock);
                return true;
            }
        }
    }

    public static void main(String[] args) {
        Inventory inventory = new Inventory(100);

        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                inventory.reduceStock(30);
            }).start();
        }
    }
}
解释:
  1. 库存初始化:初始化库存为100。
  2. 扣减操作:每个线程尝试扣减30个库存,通过CAS机制避免了多个线程同时扣减造成的竞争问题。
  3. 无锁操作:CAS的自旋重试机制使得库存扣减在并发环境下能够保持高性能,避免锁竞争。

总结

  • CAS是无锁编程的核心思想,通过硬件支持的原子操作避免了锁的开销。
  • 尽管CAS有一定局限性,如ABA问题和自旋带来的CPU消耗,但它在高并发场景下具有极高的性能优势,适用于需要频繁修改共享资源的场景。
  • 在业务场景中,CAS可以用于电商中的库存扣减、计数器实现以及无锁并发数据结构的构建

http://www.kler.cn/news/359998.html

相关文章:

  • MySQL 的系统函数
  • 快速了解Python流程控制语句基本使用
  • 【C++】在Windows中使用Boost库——实现TCP、UDP通信
  • Moectf-week1-wp
  • ENSP环回路由的配置
  • 深度学习基础—神经风格迁移
  • PCL 基于中值距离的点云对应关系(永久免费版)
  • 我常用的两个单例模式写法 (继承Mono和不继承Mono的)
  • 通过SSH远端免密登录执行脚本,修改最新5分钟生成文件权限
  • 离散数学 第二讲 特殊集合和集合间关系 笔记 [电子科大]王丽杰
  • uniapp 常用的地区行业各种多选多选,支持回显,复制粘贴可使用
  • 使用HIP和OpenMP卸载的Jacobi求解器
  • Netty笔记
  • 【论文学习与撰写】,论文word文档中出现乱码的情况,文档中显示的乱码,都是英文字母之类的,但打印预览是正常的
  • Flutter 11 Android原生项目集成Flutter Module
  • 判断索引对象中所有元素是否都为真值pandas.Index.all()
  • 【DBA Part01】国产Linux上安装Oracle进行数据迁移
  • opencv 图像缩放操作 - python 实现
  • 【STM32 HAL库】MPU6050姿态解算 卡尔曼滤波
  • vue富文本使用editor