深入理解Java AQS机制:从原理到源码解析
Java的AbstractQueuedSynchronizer
(简称AQS)是Java并发包中枢纽式的并发工具框架,被广泛应用于各种同步器与锁的实现中,如ReentrantLock
、Semaphore
、CountDownLatch
、ReadWriteLock
等。本文将从设计理念、核心数据结构、线程入队出队、状态管理、阻塞策略等多方面,结合源码解析,深入剖析AQS的实现机制,帮助你真正理解这一“神器”的本质。
一、AQS设计理念与核心技术框架
AQS的设计核心在于:
-
将同步状态的管理与线程等待队列分离
—state
用于描述同步状态,可看作“许可证”或“计数器”,子类赋予它具体语义;
— 等待队列用于保存那些等待获取锁的线程,带来了组织多个线程竞争的机制。 -
提供了独占(Exclusive)与共享(Shared)两种资源获取模式
- 独占模式:同一时间只有一个线程能持有资源,如排它锁。
- 共享模式:可以允许多个线程同时持有,如读锁、信号量。
-
基于FIFO的CLH队列实现等待排队机制
该队列采用链表结构,保证线程提交的先后顺序公平。结合LockSupport.park()/unpark()
阻塞唤醒,实现高效有序的线程管理。
二、AQS的核心数据结构解析
1. 同步状态 state
-
类型为
volatile int
,保证多线程情况下的可见性。 -
通过
getState() / setState(int)
读写,CAS操作compareAndSetState(int expect, int update)
保证状态变更的原子性。 -
state
变量含义由具体的同步器实现定义,比如:同步器 state的含义 ReentrantLock 表示锁的重入次数,0表示锁未被占用 Semaphore 表示许可数(剩余可用资源数) CountDownLatch 表示计数器,直到为0时释放等待线程 ReadWriteLock 高16位表示读锁计数,低16位表示写锁计数
2. CLH等待队列节点 Node
-
Node
是AQS的内部静态类,代表队列中的一个线程节点。 -
关键字段有:
static final class Node {static final int CANCELLED = 1;static final int SIGNAL = -1;static final int CONDITION = -2;static final int PROPAGATE = -3;volatile int waitStatus;volatile Node prev;volatile Node next;volatile Thread thread;Node nextWaiter; // 用于Condition等待队列// 标志节点类型final boolean isShared