CAS 操作在 JDK 中是通过哪个类来实现的?

参考回答

在 JDK 中,CAS(Compare-And-Swap,比较并交换)操作是通过 Unsafe 来实现的。Unsafe 是一个 Java 内部类,提供了直接操作内存和执行底层操作的能力,它是 Java 中实现 CAS 操作的核心。


详细讲解与拓展

1. 什么是 CAS?

CAS 是一种无锁的原子操作机制,常用于实现并发编程中的原子性。它的核心逻辑是:

  1. 比较内存中的值与预期值。
  2. 如果相同,就更新为新值。
  3. 如果不同,则说明其他线程已经修改过该值,CAS 操作失败。

2. CAS 在 JDK 中的实现:Unsafe

Unsafe 类简介

Unsafesun.misc 包下的一个类,提供了一些用于内存操作和底层系统交互的方法。CAS 操作是通过 Unsafe 提供的以下方法实现的:

  • compareAndSwapInt(Object obj, long offset, int expected, int newValue):比较并交换整数值。
  • compareAndSwapLong(Object obj, long offset, long expected, long newValue):比较并交换长整型值。
  • compareAndSwapObject(Object obj, long offset, Object expected, Object newValue):比较并交换对象引用。
源码示例:Unsafe 类的部分方法

以下是 compareAndSwapInt 的定义:

public final native boolean compareAndSwapInt(Object obj, long offset, int expected, int x);
  • obj:要操作的对象。
  • offset:字段在对象中的内存偏移量。
  • expected:期望值。
  • x:要更新的新值。

3. CAS 操作在 JDK 中的应用

1. AtomicInteger 的实现

CAS 操作是 java.util.concurrent.atomic 包下类的核心,例如 AtomicIntegerAtomicLong 等。

AtomicInteger 源码片段:

private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset;

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

private volatile int value;

public final int getAndIncrement() {
    return unsafe.getAndAddInt(this, valueOffset, 1);
}

public final boolean compareAndSet(int expect, int update) {
    return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}

解释:

  1. value 是一个 volatile 变量,用于保证可见性。
  2. 使用 Unsafe.compareAndSwapInt 实现了原子更新。
  3. valueOffset 表示 value 在内存中的偏移量,Unsafe 通过偏移量直接操作内存。
2. ReentrantLock 的实现

CAS 操作也被用于实现 ReentrantLock 的公平锁和非公平锁的锁竞争逻辑。

源码片段:

protected final boolean compareAndSetState(int expect, int update) {
    return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}

4. CAS 的优点与缺点

优点
  1. 无锁机制:避免了传统锁机制的阻塞问题,提高了并发性能。
  2. 高效:适合高并发场景,特别是对原子操作的需求。
缺点
  1. ABA 问题

    : 如果某个值在中间被其他线程改为另一个值再改回来,CAS 无法检测到。

  • 解决方案:引入版本号(如 AtomicStampedReference)。
  1. 自旋开销: CAS 操作可能需要反复重试,消耗 CPU 资源。

  2. 只能保证一个变量的原子性: 对于多个变量的原子操作,需要配合其他机制。


5. 小结

  • CAS 操作在 JDK 中通过 Unsafe 类实现,并用于 java.util.concurrent.atomicReentrantLock 等核心并发工具中。
  • Unsafe 提供了底层的 compareAndSwapXXX 方法,直接操作内存,实现高效的原子性操作。
  • 虽然 CAS 提高了并发性能,但也有局限性(如 ABA 问题),需要根据具体场景选择合适的并发控制方案。

发表评论

后才能评论