这三个是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 |
| 典型类 | Unsafe、AtomicXXX |
AbstractQueuedSynchronizer |
ReentrantLock、CountDownLatch |
| 使用者 | 框架开发者 | 锁实现者 | 普通开发者 |
学习路径建议
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。