多线程(七)AQS
AQS(AbstractQueuedSynchronizer,抽象队列同步器) 是 Java 并发包(java.util.concurrent)的绝对核心。ReentrantLock、CountDownLatch、Semaphore、ReentrantReadWriteLock 等底层全部依赖 AQS
一、 核心思想:模板方法模式
-
AQS 负责:维护同步状态(
state)、管理线程的排队与阻塞、唤醒。 -
子类负责:定义什么是“获取锁成功”和“释放锁成功”(即如何操作
state)。
AQS 定义了几个关键方法,子类可以选择性重写(以下方法在 AQS 中默认抛出 UnsupportedOperationException,强制子类按需实现):
tryAcquire(int) |
独占模式获取锁(如 ReentrantLock) |
tryRelease(int) |
独占模式释放锁 |
tryAcquireShared(int) |
共享模式获取锁(如 Semaphore、CountDownLatch) |
tryReleaseShared(int) |
共享模式释放锁 |
isHeldExclusively() |
是否被当前线程独占 |
protected boolean isHeldExclusively() { throw new UnsupportedOperationException(); }
二、 核心结构
示例代码取自JDK21
1. volatile int state(同步状态)
/** * The synchronization state. */ private volatile int state;
不同的工具赋予它不同的含义:
-
ReentrantLock:state = 0表示无锁,state > 0表示锁被重入次数。【独占模式】
final boolean tryLock() { Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (compareAndSetState(0, 1)) { setExclusiveOwnerThread(current); return true; } } else if (getExclusiveOwnerThread() == current) { if (++c < 0) // overflow throw new Error("Maximum lock count exceeded"); setState(c); return true; } return false; }
-
Semaphore:state表示可用许可数量。 -
CountDownLatch:state表示剩余计数。【共享模式】
/**
* Synchronization control For CountDownLatch.
* Uses AQS state to represent count.
*/
int getCount() { return getState(); } protected int tryAcquireShared(int acquires) { return (getState() == 0) ? 1 : -1; }
2. FIFO 双向队列
当线程获取锁失败时,会被包装成 Node 节点,加入队列尾部等待。
abstract static class Node { volatile Node prev; // initially attached via casTail volatile Node next; // visibly nonnull when signallable Thread waiter; // visibly nonnull when enqueued volatile int status; // written by owner, atomic bit ops by others // methods for atomic operations final boolean casPrev(Node c, Node v) { // for cleanQueue return U.weakCompareAndSetReference(this, PREV, c, v); } final boolean casNext(Node c, Node v) { // for cleanQueue return U.weakCompareAndSetReference(this, NEXT, c, v); } final int getAndUnsetStatus(int v) { // for signalling return U.getAndBitwiseAndInt(this, STATUS, ~v); } final void setPrevRelaxed(Node p) { // for off-queue assignment U.putReference(this, PREV, p); } final void setStatusRelaxed(int s) { // for off-queue assignment U.putInt(this, STATUS, s); } final void clearStatus() { // for reducing unneeded signals U.putIntOpaque(this, STATUS, 0); } private static final long STATUS = U.objectFieldOffset(Node.class, "status"); private static final long NEXT = U.objectFieldOffset(Node.class, "next"); private static final long PREV = U.objectFieldOffset(Node.class, "prev"); }
JDK 21 AQS Node 的核心变化
| 字段 | JDK 8 | JDK 21 | 变化原因 |
|---|---|---|---|
prev |
volatile Node prev |
volatile Node prev |
保持不变 |
next |
volatile Node next |
volatile Node next |
保持不变 |
| 线程字段 | volatile Thread thread |
Thread waiter(去 volatile) |
利用 prev/next 的 volatile 保证可见性,减少开销 |
| 状态字段 | volatile int waitStatus |
volatile int status(支持位运算) |
支持更复杂的状态组合与原子位操作 |
3. Unsafe + CAS(原子操作)
AQS 使用 Unsafe.compareAndSwapInt 等底层 CAS 操作来修改 state 和队列指针,保证线程安全。
protected final boolean compareAndSetState(int expect, int update) { return U.compareAndSetInt(this, STATE, expect, update); }
AQS 内部有一个 volatile int state 表示同步状态,和一个 FIFO 队列管理等待线程。由于 volatile 只保证可见性不保证原子性,AQS 通过调用 Unsafe 类提供的 CAS 方法(底层是 CPU 的 cmpxchg 指令),以无锁、原子的方式修改 state(抢锁)和队列指针(入队/出队)。CAS 成功则继续执行,失败则自旋重试或进入队列等待。这种设计避免了 synchronized 重量级锁的挂起/唤醒开销,是 AQS 高性能的根本原因。
三、 编码实例
ReentrantLock
import java.util.concurrent.locks.ReentrantLock; public class ReentrantLockBasicDemo { // 定义锁(通常作为成员变量,static final 或实例字段) private final ReentrantLock lock = new ReentrantLock(); private int count = 0; public void increment() { lock.lock(); // 加锁 try { count++; // 临界区代码 } finally { lock.unlock(); // 必须放在 finally 中,防止异常导致死锁 } } public int getCount() { lock.lock(); try { return count; } finally { lock.unlock(); } } public static void main(String[] args) throws InterruptedException { ReentrantLockBasicDemo demo = new ReentrantLockBasicDemo(); Thread[] threads = new Thread[10]; for (int i = 0; i < 10; i++) { threads[i] = new Thread(() -> { for (int j = 0; j < 1000; j++) { demo.increment(); } }); threads[i].start(); } for (Thread t : threads) t.join(); System.out.println("最终 count = " + demo.getCount()); // 10000 } }
countDownLanch
import java.util.concurrent.CountDownLatch; public class CountDownLatchBasic { public static void main(String[] args) throws InterruptedException { int workerCount = 3; CountDownLatch latch = new CountDownLatch(workerCount); // 启动 3 个工作线程 for (int i = 1; i <= workerCount; i++) { final int id = i; new Thread(() -> { try { System.out.println("工人" + id + " 开始工作..."); Thread.sleep(1000 * id); // 模拟不同耗时 System.out.println("工人" + id + " 工作完成"); } catch (InterruptedException e) { e.printStackTrace(); } finally { latch.countDown(); // 关键:完成后计数减 1 } }).start(); } System.out.println("主线程等待所有工人完成..."); latch.await(); // 阻塞,直到计数器归零 System.out.println("所有工人完成,主线程继续执行"); } }

浙公网安备 33010602011771号