Java随笔-CAS&AQS

一、CAS(Compare And Swap)

1. 基本概念

CAS 是一种乐观锁实现,包含三个操作数:

  • 内存值 V(当前主内存中的值)
  • 预期值 A(线程本地记录的旧值)
  • 新值 B(要更新的值)

核心逻辑:只有当 V == A 时,才将 V 更新为 B,否则重试。

2. 底层实现

java 复制代码
// Unsafe 类中的 CAS 操作(底层调用 CPU 指令)
public final native boolean compareAndSwapInt(Object o, long offset, int expected, int x);

硬件层面:现代 CPU 提供 cmpxchg 指令(x86)或 LDREX/STREX(ARM),保证操作的原子性。

3. 典型应用

说明
AtomicInteger / AtomicLong 原子整型
AtomicReference 原子引用
AtomicStampedReference 解决 ABA 问题(带版本号)
ConcurrentHashMap 分段锁 + CAS 优化

ABA 问题

问题描述 :值从 A → B → A,CAS 检测不出变化。

解决方案:AtomicStampedReference 增加版本号/时间戳。

java 复制代码
AtomicStampedReference<Integer> ref = new AtomicStampedReference<>(100, 0);
int[] stampHolder = new int[1];
Integer value = ref.get(stampHolder); // 获取值和版本号
ref.compareAndSet(100, 200, stampHolder[0], stampHolder[0] + 1);
5. CAS 的优缺点
优点 缺点
无锁,性能高(无线程切换开销) 只能保证单个变量的原子性
非阻塞,不会死锁 循环重试消耗 CPU(自旋)
存在 ABA 问题

二、AQS(AbstractQueuedSynchronizer)

1. 基本概念

AQS 是 JUC 并发包的基石 ,是一个用于构建锁和同步器的抽象框架

核心设计:

  • state 变量:int 类型,表示同步状态(如重入锁的重入次数、信号量的许可数)
  • FIFO 队列:CLH 变体的双向链表,管理等待线程
  • 模板方法模式:子类只需实现特定方法

2. 核心结构

3. 两种模式

模式 说明 代表类
独占模式 同一时间只有一个线程能获取 ReentrantLock
共享模式 多个线程可同时获取 SemaphoreCountDownLatch

4. 核心方法(子类需实现)

java 复制代码
// 独占模式
protected boolean tryAcquire(int arg);      // 获取锁
protected boolean tryRelease(int arg);      // 释放锁

// 共享模式
protected int tryAcquireShared(int arg);    // 获取共享锁
protected boolean tryReleaseShared(int arg); // 释放共享锁

// 通用
protected boolean isHeldExclusively();      // 是否被独占

5. 队列节点(Node)状态

状态 含义
CANCELLED 1 节点被取消(超时或中断)
SIGNAL -1 后继节点需要被唤醒
CONDITION -2 在 Condition 队列中
PROPAGATE -3 共享模式传播

6. 获取锁的流程(以 ReentrantLock 为例)

7. 核心源码分析

java 复制代码
// AQS 获取锁的入口
public final void acquire(int arg) {
    if (!tryAcquire(arg) &&           // 1. 快速尝试获取
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))  // 2. 入队 + 排队获取
        selfInterrupt();              // 3. 恢复中断状态
}

// 入队操作(CAS 保证线程安全)
private Node addWaiter(Node mode) {
    Node node = new Node(Thread.currentThread(), mode);
    Node pred = tail;
    if (pred != null) {
        node.prev = pred;
        if (compareAndSetTail(pred, node)) {  // CAS 入队
            pred.next = node;
            return node;
        }
    }
    enq(node);  // 初始化或重试
    return node;
}

8. AQS 应用

同步器 模式 用途
ReentrantLock 独占 可重入互斥锁
ReentrantReadWriteLock 独占+共享 读写分离锁
Semaphore 共享 限流/资源池
CountDownLatch 共享 等待多线程完成
CyclicBarrier 共享 线程互相等待
Phaser 共享 分阶段任务

三、CAS vs AQS

维度 CAS AQS
层级 底层原子操作 上层同步框架
机制 乐观锁(无锁) 悲观锁 + 队列
适用场景 简单变量更新 复杂同步控制
线程冲突 重试(自旋) 阻塞( park/unpark )
CPU 消耗 高冲突时较高 阻塞后较低
关系 AQS 内部用 CAS 维护 state 和队列

四、实际应用

1. 基于 CAS 的原子计数器

java 复制代码
AtomicInteger counter = new AtomicInteger(0);
// 底层:CAS 循环直到成功
counter.incrementAndGet();

基于 AQS 的自定义锁

java 复制代码
class SimpleLock extends AbstractQueuedSynchronizer {
    @Override
    protected boolean tryAcquire(int arg) {
        return compareAndSetState(0, 1);  // CAS 修改 state
    }
    
    @Override
    protected boolean tryRelease(int arg) {
        setState(0);
        return true;
    }
    
    public void lock() { acquire(1); }
    public void unlock() { release(1); }
}

五、总结

  • CAS 是 Java 实现无锁并发的底层利器,适用于低竞争、简单场景
  • AQS 是构建复杂同步器的框架,通过 state + CLH 队列 + CAS 实现了高效的线程阻塞与唤醒
  • 两者相辅相成:AQS 内部大量依赖 CAS 操作(如 compareAndSetState、compareAndSetTail)