【HashMap】CAS的定义及优缺点

CAS(Compare-And-Swap,比较并交换)是一种原子操作,用于实现无锁(lock-free)的并发数据结构。它是现代处理器支持的一种硬件指令,能够保证在多线程环境下进行变量更新时的原子性。CAS 操作包含三个操作数:

  1. 内存位置(变量的地址)。
  2. 预期值(期望该内存位置的当前值)。
  3. 新值(希望设置的新值)。

CAS 操作的逻辑是:如果内存位置的当前值与预期值相等,那么将内存位置的值更新为新值;否则,不进行任何操作,并返回当前内存位置的值。这一过程是原子的,即在多线程环境下同时只能有一个 CAS 操作成功。

为什么使用 CAS 操作?

CAS 操作主要用于无锁编程。相比传统的锁机制,CAS 具有以下优势:

  • 无锁并发:避免了线程切换和调度带来的开销,提高了系统的吞吐量和性能。
  • 避免死锁:由于不需要锁定资源,因此不存在死锁的风险。
  • 更好的可伸缩性:特别适用于高并发环境。

CAS 的缺点

尽管 CAS 操作有很多优点,但也有一些缺点:

  • ABA 问题:在 CAS 操作过程中,如果一个变量的值从 A 变成 B,然后又变回 A,CAS 操作会认为值没有变化,从而导致错误。解决 ABA 问题的一种常用方法是使用版本号,每次更新值时同时更新版本号。
  • 自旋开销:如果 CAS 操作不断失败(例如在高竞争环境下),会导致自旋开销,浪费 CPU 资源。

Java 中的 CAS 操作

在 Java 中,CAS 操作主要通过 java.util.concurrent.atomic 包下的原子类来实现,例如 AtomicIntegerAtomicReference 等。底层实现依赖于 Unsafe 类中的 compareAndSwapIntcompareAndSwapLongcompareAndSwapObject 等方法。

以下是一个使用 AtomicInteger 的简单示例:

java 复制代码
import java.util.concurrent.atomic.AtomicInteger;

public class CASExample {
    private AtomicInteger atomicInteger = new AtomicInteger(0);

    public void increment() {
        int expectedValue;
        int newValue;
        do {
            expectedValue = atomicInteger.get();
            newValue = expectedValue + 1;
        } while (!atomicInteger.compareAndSet(expectedValue, newValue));
    }

    public int getValue() {
        return atomicInteger.get();
    }

    public static void main(String[] args) {
        CASExample example = new CASExample();
        example.increment();
        System.out.println(example.getValue()); // 输出1
    }
}

在上述代码中:

  • AtomicInteger 提供了一个原子整数,可以安全地在多线程环境下使用。
  • compareAndSet 方法实现了 CAS 操作。它会比较当前值与预期值,如果相等,则更新为新值;否则,返回 false 并重试(通过 do-while 循环)。

Java 中 CAS 的底层实现

Java 中的 CAS 操作最终依赖于 JVM 的 Unsafe 类。Unsafe 类提供了一些底层操作方法,这些方法直接调用处理器的 CAS 指令。以下是一个简化的 CAS 实现示例:

java 复制代码
import sun.misc.Unsafe;

public class SimpleCAS {
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    private volatile int value;

    private static final long valueOffset;

    static {
        try {
            valueOffset = unsafe.objectFieldOffset(SimpleCAS.class.getDeclaredField("value"));
        } catch (Exception ex) {
            throw new Error(ex);
        }
    }

    public int getValue() {
        return value;
    }

    public boolean compareAndSet(int expected, int newValue) {
        return unsafe.compareAndSwapInt(this, valueOffset, expected, newValue);
    }

    public static void main(String[] args) {
        SimpleCAS cas = new SimpleCAS();
        cas.value = 5;
        boolean result = cas.compareAndSet(5, 10);
        System.out.println("CAS successful: " + result);
        System.out.println("New value: " + cas.getValue());
    }
}

在上述代码中:

  • Unsafe 类的 compareAndSwapInt 方法用于实现 CAS 操作。
  • valueOffsetvalue 字段在 SimpleCAS 类中的内存偏移量,用于 Unsafe 方法定位。

通过上述方法,Java 提供了一种高效的方式来进行原子操作,从而实现无锁的并发编程。

相关推荐
腻害兔7 小时前
【若依项目-产品经理视角】深度拆解 RuoYi-Vue-Pro 商城模块:从商品管理到交易引擎,50 张表撑起一整套电商系统
java·大数据·vue.js·产品经理·ai编程
码智社8 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
萧瑟余晖9 小时前
JDK 26 新特性详解
java·开发语言
马优晨9 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
维天说12 小时前
CLI-Switch 2026年3月版历史设计:Hook、TTY 隔离与 JSON 状态
java·服务器·json
Zane199413 小时前
并发 vs 并行:别再傻傻分不清了,一文讲透 Java 并发编程的第一课
java·后端
噢,我明白了14 小时前
java中Excel的导入和导出(EasyExcel)
java·开发语言·excel
吠品14 小时前
Zabbix Web界面误报Server未运行的排查与解决
java·服务器·数据库
啊湘14 小时前
天气查询API接口 按月Token鉴权 实时天气 物联网可用 文档齐全
java·后端·struts
Java内核笔记14 小时前
告别十亿美元的错误 : Spring Boot 4 空安全 (JSpecify) 实战
java·spring boot·后端