Java并发编程核心:JUC、AQS、CAS 完全指南

这三个是Java并发编程的核心基础,层层递进的关系:

  • CAS:最底层的原子操作(硬件级支持)

  • AQS:基于CAS构建的同步器框架(抽象层)

  • JUC包:基于AQS实现的各种并发工具(应用层)

一、CAS(Compare And Swap,比较并交换)

是什么

CPU级别的原子指令,用于实现无锁编程。它包含三个操作数:

  • 内存地址 V

  • 期望值 A

  • 新值 B

执行逻辑:如果V的值等于A,则将V更新为B,否则什么都不做。整个过程是原子的。

底层实现

复制代码
// 使用AtomicStampedReference(带版本号)
AtomicStampedReference<String> ref = new AtomicStampedReference<>("A", 1);
int stamp = ref.getStamp();
ref.compareAndSet("A", "B", stamp, stamp + 1);

// Java中的CAS(通过Unsafe类调用CPU指令)
public final native boolean compareAndSwapInt(Object obj, long offset, int expect, int update);

CPU指令

  • x86:lock cmpxchg

  • ARM:LDREX/STREX

典型应用:AtomicInteger

复制代码
// AtomicInteger的incrementAndGet()底层就是CAS
AtomicInteger count = new AtomicInteger(0);
count.incrementAndGet();  // CAS自旋实现

// 手写CAS
public void casExample() {
    AtomicInteger atomicInt = new AtomicInteger(5);
    boolean success = atomicInt.compareAndSet(5, 10);  // 期望是5,则设为10
    System.out.println(success);  // true
}

// 使用CAS实现原子自增
public class AtomicInteger {
    private volatile int value;
    
    public final int incrementAndGet() {
        for (;;) {  // 自旋
            int current = value;
            int next = current + 1;
            if (compareAndSet(current, next)) {
                return next;
            }
        }
    }
    
    public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }
}

优点与缺点

优点 缺点
无锁,避免线程切换开销 ABA问题(值从A→B→A,CAS误认为没变)
高性能,适合短临界区 自旋会浪费CPU
不会死锁 只能保证单个变量的原子性

ABA问题解决方案

复制代码
// 使用AtomicStampedReference(带版本号)
AtomicStampedReference<String> ref = new AtomicStampedReference<>("A", 1);
int stamp = ref.getStamp();
ref.compareAndSet("A", "B", stamp, stamp + 1);

二、AQS(AbstractQueuedSynchronizer,抽象队列同步器)

是什么

AQS(AbstractQueuedSynchronizer)是JUC包的基石,是一个抽象类,提供了:

  • 同步状态管理volatile int state

  • FIFO等待队列(CLH队列变种)

  • 阻塞/唤醒机制LockSupport.park()/unpark()

核心组件

复制代码
┌─────────────────────────────────────────────────┐
│                 AQS (抽象类)                     │
├─────────────────────────────────────────────────┤
│  volatile int state           // 同步状态         │
│                                                 │
│  ┌──────┐    ┌──────┐    ┌──────┐              │
│  │ Node │ →  │ Node │ →  │ Node │   // 等待队列 │
│  │thread│    │thread│    │thread│              │
│  └──────┘    └──────┘    └──────┘              │
│  head                           tail            │
│                                                 │
│  + tryAcquire()    // 尝试获取(需重写)         │
│  + tryRelease()    // 尝试释放(需重写)         │
│  + acquire()       // 获取模板方法              │
│  + release()       // 释放模板方法              │
└─────────────────────────────────────────────────┘

核心方法

方法 说明 是否需要重写
tryAcquire(int arg) 尝试获取资源 ✅ 需要
tryRelease(int arg) 尝试释放资源 ✅ 需要
tryAcquireShared(int arg) 尝试获取共享资源 ✅ 需要
tryReleaseShared(int arg) 尝试释放共享资源 ✅ 需要
isHeldExclusively() 是否被当前线程独占 ✅ 需要
acquire(int arg) 获取资源模板(失败入队) ❌ 框架提供
release(int arg) 释放资源模板 ❌ 框架提供

两种资源共享模式

模式 说明 典型实现
独占模式(Exclusive) 同一时刻只能一个线程持有 ReentrantLock
共享模式(Shared) 多个线程可同时持有 CountDownLatch、Semaphore、ReadLock

自定义AQS锁示例

复制代码
// 自定义不可重入互斥锁
public class SimpleMutexLock extends AbstractQueuedSynchronizer {
    
    @Override
    protected boolean tryAcquire(int unused) {
        // CAS设置state从0→1,成功则获得锁
        return compareAndSetState(0, 1);
    }
    
    @Override
    protected boolean tryRelease(int unused) {
        setState(0);  // 释放锁
        return true;
    }
    
    @Override
    protected boolean isHeldExclusively() {
        return getState() == 1;
    }
    
    public void lock() { 
        acquire(1); 
    }
    
    public void unlock() { 
        release(1); 
    }
}

// 使用示例
SimpleMutexLock lock = new SimpleMutexLock();
lock.lock();
try {
    // 临界区
} finally {
    lock.unlock();
}

AQS内部等待队列原理

复制代码
     ┌──────┐    ┌──────┐    ┌──────┐
head │ Node │ →  │ Node │ →  │ Node │ tail
     └──────┘    └──────┘    └──────┘
        ↑            ↑            ↑
      prev          prev         prev
  • 每个Node包装一个等待线程

  • 获取锁失败时,线程入队并LockSupport.park()

  • 锁释放时,唤醒head的后继节点

AQS源码简析(acquire流程)

复制代码
// AQS的acquire模板方法
public final void acquire(int arg) {
    if (!tryAcquire(arg) &&                    // 1. 尝试获取锁
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))  // 2. 失败则入队
        selfInterrupt();                       // 3. 中断当前线程
}

// 入队并阻塞
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;
}

三、JUC包(java.util.concurrent)

是什么

Java 5引入的并发工具包,包含锁、原子类、并发集合、线程池等。大部分底层依赖AQS和CAS。

JUC包结构

复制代码
java.util.concurrent
├── locks          # 锁相关
│   ├── ReentrantLock
│   ├── ReentrantReadWriteLock
│   └── StampedLock
├── atomic         # 原子类
│   ├── AtomicInteger
│   ├── AtomicLong
│   ├── LongAdder
│   └── AtomicStampedReference
├── tools          # 同步工具
│   ├── CountDownLatch
│   ├── CyclicBarrier
│   ├── Semaphore
│   └── Exchanger
├── collections    # 并发集合
│   ├── ConcurrentHashMap
│   ├── ConcurrentLinkedQueue
│   ├── CopyOnWriteArrayList
│   └── BlockingQueue (及实现)
└── executor       # 线程池
    ├── ThreadPoolExecutor
    ├── ScheduledThreadPoolExecutor
    └── ForkJoinPool

JUC包主要组件

分类 类/接口 底层依赖
ReentrantLock AQS
ReentrantReadWriteLock AQS
StampedLock 自定义(非AQS)
原子类 AtomicInteger、AtomicLong CAS
AtomicReference、AtomicStampedReference CAS
LongAdder CAS + 分段思想
同步工具 CountDownLatch AQS(共享模式)
CyclicBarrier ReentrantLock + Condition
Semaphore AQS(共享模式)
Exchanger CAS + 自旋
并发集合 ConcurrentHashMap CAS + synchronized
ConcurrentLinkedQueue CAS
CopyOnWriteArrayList ReentrantLock
线程池 ThreadPoolExecutor BlockingQueue + ReentrantLock
阻塞队列 ArrayBlockingQueue ReentrantLock
LinkedBlockingQueue ReentrantLock

典型使用示例

复制代码
// 1. ReentrantLock(AQS独占模式)
ReentrantLock lock = new ReentrantLock();
lock.lock();
try {
    // 业务
} finally {
    lock.unlock();
}

// 2. CountDownLatch(AQS共享模式)
CountDownLatch latch = new CountDownLatch(3);
for (int i = 0; i < 3; i++) {
    new Thread(() -> {
        // 准备工作
        latch.countDown();
    }).start();
}
latch.await();  // 等待3个线程都完成

// 3. AtomicInteger(CAS)
AtomicInteger atomicInt = new AtomicInteger(0);
int prev = atomicInt.getAndIncrement();  // CAS自旋

// 4. ConcurrentHashMap(CAS + synchronized)
ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();
map.putIfAbsent("key", "value");  // CAS实现

完整示例:从CAS到AQS到JUC

复制代码
public class ConcurrencyDemo {
    
    // 1. 最底层:CAS手动实现计数器
    static class CasCounter {
        private volatile int value;
        private static final Unsafe unsafe = ...;
        
        public void increment() {
            for (;;) {
                int current = value;
                if (unsafe.compareAndSwapInt(this, offset, current, current + 1)) {
                    break;
                }
            }
        }
    }
    
    // 2. 中间层:基于AQS实现简单锁
    static class SimpleLock extends AbstractQueuedSynchronizer {
        @Override
        protected boolean tryAcquire(int arg) {
            return compareAndSetState(0, 1);
        }
        @Override
        protected boolean tryRelease(int arg) {
            setState(0);
            return true;
        }
        public void lock() { acquire(1); }
        public void unlock() { release(1); }
    }
    
    // 3. 应用层:直接使用JUC工具
    static class JucCounter {
        private final AtomicInteger count = new AtomicInteger(0);
        public void increment() {
            count.incrementAndGet();  // CAS实现
        }
    }
    
    public static void main(String[] args) {
        // 使用JUC工具
        ReentrantLock lock = new ReentrantLock();
        lock.lock();
        try {
            System.out.println("Hello JUC");
        } finally {
            lock.unlock();
        }
    }
}

三者的关系图

复制代码
                    ┌─────────────────────────────────┐
                    │           JUC 工具包             │
                    │  ReentrantLock  CountDownLatch   │
                    │  Semaphore      ConcurrentHashMap│
                    │  AtomicInteger  ThreadPoolExecutor│
                    └────────────────┬────────────────┘
                                     │ 基于
                                     ▼
                    ┌─────────────────────────────────┐
                    │            AQS (框架)            │
                    │  (AbstractQueuedSynchronizer)    │
                    │  - volatile int state            │
                    │  - FIFO等待队列                  │
                    │  - acquire()/release()模板       │
                    └────────────────┬────────────────┘
                                     │ 底层调用
                                     ▼
                    ┌─────────────────────────────────┐
                    │              CAS (原子操作)      │
                    │  (Compare And Swap)              │
                    │  - CPU原子指令 (cmpxchg)         │
                    │  - Unsafe.compareAndSwapInt()    │
                    └─────────────────────────────────┘

核心区别总结

维度 CAS AQS JUC
定位 原子操作(底层) 同步器框架(中层) 并发工具集(上层)
作用 实现无锁更新 提供锁的骨架实现 提供开箱即用的并发工具
依赖 依赖CPU指令 依赖CAS 依赖AQS和CAS
典型类 UnsafeAtomicXXX AbstractQueuedSynchronizer ReentrantLockCountDownLatch
使用者 框架开发者 锁实现者 普通开发者

学习路径建议

复制代码
1. 先掌握基础
   └── volatile、synchronized、wait/notify

2. 理解CAS原理
   └── AtomicInteger源码、ABA问题

3. 深入AQS框架
   └── ReentrantLock源码、CLH队列

4. 熟练使用JUC工具
   └── CountDownLatch、Semaphore、ConcurrentHashMap

5. 实战应用
   └── 线程池、生产者消费者、缓存设计

一句话总结

  • CAS:硬件级的原子操作,是地基

  • AQS:基于CAS构建的同步器框架,是骨架

  • JUC:基于AQS提供的现成并发工具,是成品

普通开发者直接用JUC 包里的工具就够了;如果要实现自定义锁,需要理解AQS ;如果想深入底层优化,需要掌握CAS

相关推荐
鱼鳞_2 小时前
Java学习笔记_Day35(多线程)
java·笔记·学习
木易 士心2 小时前
MyBatis Plus 核心功能与用法
java·后端·mybatis
下次再写2 小时前
互联网大厂Java面试三轮技术问答及详解——涵盖Spring Boot与微服务
java·springboot·microservices·interview
林深时见鹿v2 小时前
《后端开发全栈工具安装踩坑指南 & 经验沉淀手册》
java·人工智能·python·oracle
云深麋鹿2 小时前
C++ | 容器stack&queue
开发语言·c++
比老马还六2 小时前
element-ui,使用el-table时,type=“expand“和fixed一起使用坑
开发语言·javascript·ui
Xiu Yan2 小时前
Java 转 C++ 系列:STL容器之list
java·开发语言·数据结构·c++·stl·list·visual studio
搬砖小郭2 小时前
从0到1的springboot项目搭建到打包
java
小芝麻咿呀2 小时前
边缘计算网关-EG8200Mini导轨版
java·人工智能·边缘计算