Skip to content

CAS操作面试题

1. CAS的基本概念

问题:什么是CAS?

答案

  • CAS(Compare-And-Swap):比较并交换,是一种无锁的并发算法。
  • 作用
    • 实现无锁并发
    • 避免线程阻塞
    • 提高并发性能
  • 原理
    1. 读取当前值
    2. 比较当前值和期望值
    3. 如果相等,更新为新值
    4. 如果不等,重试

2. CAS的实现原理

问题:CAS是如何实现的?

答案

  • 硬件支持
    • CAS依赖CPU的原子指令
    • x86架构:CMPXCHG指令
    • ARM架构:LDREX/STREX指令
  • Java实现
    • Unsafe类提供CAS操作
    • Atomic类基于Unsafe实现

示例

java
// CAS的伪代码实现
public boolean compareAndSwap(int[] arr, int index, int expected, int newValue) {
    if (arr[index] == expected) {
        arr[index] = newValue;
        return true;
    }
    return false;
}

3. CAS的Java实现

问题:Java中如何使用CAS?

答案

java
// 使用Unsafe类
public class CASExample {
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    private static final long valueOffset;
    
    static {
        try {
            valueOffset = unsafe.objectFieldOffset(CASExample.class.getDeclaredField("value"));
        } catch (Exception e) {
            throw new Error(e);
        }
    }
    
    private volatile int value;
    
    public boolean compareAndSwap(int expected, int newValue) {
        return unsafe.compareAndSwapInt(this, valueOffset, expected, newValue);
    }
}

// 使用Atomic类
AtomicInteger atomicInteger = new AtomicInteger(0);
boolean success = atomicInteger.compareAndSet(0, 1);

4. Atomic类

问题:Java提供了哪些Atomic类?

答案

  • 基本类型
    • AtomicInteger
    • AtomicLong
    • AtomicBoolean
  • 数组类型
    • AtomicIntegerArray
    • AtomicLongArray
    • AtomicReferenceArray
  • 引用类型
    • AtomicReference
    • AtomicStampedReference
    • AtomicMarkableReference
  • 字段更新器
    • AtomicIntegerFieldUpdater
    • AtomicLongFieldUpdater
    • AtomicReferenceFieldUpdater
  • 累加器
    • LongAdder
    • DoubleAdder
    • LongAccumulator
    • DoubleAccumulator

5. AtomicInteger的使用

问题:如何使用AtomicInteger?

答案

java
AtomicInteger atomicInteger = new AtomicInteger(0);

// 获取值
int value = atomicInteger.get();

// 设置值
atomicInteger.set(10);

// CAS操作
boolean success = atomicInteger.compareAndSet(0, 1);

// 原子加
int result = atomicInteger.getAndIncrement();
int result = atomicInteger.incrementAndGet();

// 原子减
int result = atomicInteger.getAndDecrement();
int result = atomicInteger.decrementAndGet();

// 原子加指定值
int result = atomicInteger.getAndAdd(5);
int result = atomicInteger.addAndGet(5);

// 原子更新
int result = atomicInteger.getAndUpdate(x -> x * 2);
int result = atomicInteger.updateAndGet(x -> x * 2);

6. AtomicReference的使用

问题:如何使用AtomicReference?

答案

java
class User {
    private String name;
    private int age;
    
    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

AtomicReference<User> userRef = new AtomicReference<>(new User("John", 30));

// 获取值
User user = userRef.get();

// CAS操作
User newUser = new User("Jane", 25);
boolean success = userRef.compareAndSet(user, newUser);

// 原子更新
User result = userRef.getAndUpdate(u -> new User(u.name, u.age + 1));

7. AtomicIntegerArray的使用

问题:如何使用AtomicIntegerArray?

答案

java
int[] array = new int[10];
AtomicIntegerArray atomicArray = new AtomicIntegerArray(array);

// 获取值
int value = atomicArray.get(0);

// 设置值
atomicArray.set(0, 10);

// CAS操作
boolean success = atomicArray.compareAndSet(0, 10, 20);

// 原子加
int result = atomicArray.getAndIncrement(0);
int result = atomicArray.incrementAndGet(0);

8. AtomicStampedReference的使用

问题:什么是ABA问题?如何解决?

答案

  • ABA问题
    • 一个值从A变成B,又变回A
    • CAS无法检测到这种变化
  • 解决方案
    • 使用版本号
    • 使用AtomicStampedReference

示例

java
AtomicStampedReference<String> stampedRef = new AtomicStampedReference<>("A", 0);

// 获取值和版本号
String value = stampedRef.getReference();
int stamp = stampedRef.getStamp();

// CAS操作
boolean success = stampedRef.compareAndSet("A", "B", 0, 1);

9. LongAdder的使用

问题:什么是LongAdder?何时使用?

答案

  • LongAdder:高并发场景下的累加器,性能优于AtomicLong。
  • 适用场景
    • 高并发累加
    • 统计计数
  • 原理
    • 分散竞争
    • 减少CAS失败

示例

java
LongAdder adder = new LongAdder();

// 累加
adder.add(1);
adder.add(2);

// 获取值
long sum = adder.sum();

// 重置
adder.reset();

10. CAS的优缺点

问题:CAS有哪些优缺点?

答案

  • 优点
    • 无锁,避免线程阻塞
    • 性能高
    • 适合低竞争场景
  • 缺点
    • 高竞争时性能下降
    • 只能保证单个变量的原子性
    • ABA问题
    • CPU开销大

11. CAS的ABA问题

问题:什么是ABA问题?

答案

  • ABA问题
    • 一个值从A变成B,又变回A
    • CAS无法检测到这种变化
    • 可能导致数据不一致
  • 解决方法
    • 使用版本号
    • 使用AtomicStampedReference
    • 使用AtomicMarkableReference

示例

java
// ABA问题示例
AtomicInteger atomicInteger = new AtomicInteger(100);

// 线程1:100 -> 101 -> 100
atomicInteger.compareAndSet(100, 101);
atomicInteger.compareAndSet(101, 100);

// 线程2:CAS成功,但值已经被修改过
boolean success = atomicInteger.compareAndSet(100, 200);

12. CAS的自旋锁

问题:如何使用CAS实现自旋锁?

答案

java
class SpinLock {
    private final AtomicReference<Thread> owner = new AtomicReference<>();
    
    public void lock() {
        Thread currentThread = Thread.currentThread();
        while (!owner.compareAndSet(null, currentThread)) {
            // 自旋等待
        }
    }
    
    public void unlock() {
        Thread currentThread = Thread.currentThread();
        owner.compareAndSet(currentThread, null);
    }
}

13. CAS的性能问题

问题:CAS在什么情况下性能会下降?

答案

  • 高竞争
    • 多个线程同时修改同一个变量
    • CAS失败率高
    • 自旋时间长
  • 解决方案
    • 减少竞争
    • 使用分段锁
    • 使用LongAdder

14. CAS的内存语义

问题:CAS的内存语义是什么?

答案

  • volatile语义
    • CAS操作具有volatile语义
    • 保证可见性
    • 保证有序性
  • happens-before原则
    • CAS操作之前的操作对CAS操作可见
    • CAS操作之后的操作对CAS操作可见

15. CAS与synchronized的区别

问题:CAS和synchronized有什么区别?

答案

  • CAS
    • 无锁
    • 非阻塞
    • 适合低竞争
    • 只能保证单个变量的原子性
  • synchronized
    • 有锁
    • 阻塞
    • 适合高竞争
    • 可以保证代码块的原子性

16. CAS的使用场景

问题:CAS适合哪些场景?

答案

  • 计数器
    • 并发计数
    • 使用AtomicInteger
  • 序列号生成
    • 原子递增
    • 使用AtomicLong
  • 状态标志
    • 状态切换
    • 使用AtomicBoolean
  • 引用更新
    • 原子更新引用
    • 使用AtomicReference

17. CAS的局限性

问题:CAS有哪些局限性?

答案

  • ABA问题
    • 无法检测值的变化
  • 只能保证单个变量的原子性
    • 无法保证多个变量的原子性
  • 高竞争性能差
    • CAS失败率高
    • 自旋时间长
  • CPU开销大
    • 自旋占用CPU

18. CAS的优化

问题:如何优化CAS性能?

答案

  • 减少竞争
    • 使用分段锁
    • 使用ThreadLocal
  • 使用LongAdder
    • 高并发累加
    • 分散竞争
  • 限制自旋次数
    • 避免无限自旋
    • 自旋一定次数后阻塞

19. CAS在Java中的应用

问题:CAS在Java中有哪些应用?

答案

  • 并发包
    • AtomicInteger
    • AtomicLong
    • AtomicReference
  • 集合类
    • ConcurrentHashMap
    • ConcurrentLinkedQueue
  • 锁实现
    • ReentrantLock
    • StampedLock

20. CAS的最佳实践

问题:使用CAS的最佳实践有哪些?

答案

  • 选择合适的Atomic类。
  • 避免ABA问题,使用AtomicStampedReference。
  • 高并发累加使用LongAdder。
  • 高竞争场景使用synchronized。
  • 限制自旋次数,避免CPU浪费。
  • 理解CAS的内存语义。
  • 合理使用CAS的原子方法。
  • 注意CAS的局限性。
  • 根据场景选择合适的并发工具。