AQS就是使用一个state值,和FIFO队列来实现多线程下对共享资源的访问。并且state值是被volatile修饰。主要实现有独占模式和共享模式。在独占模式下,如果线程想要获取锁需要通过cas的方式修改state值为1,并设置持有锁的线程为当前线程,释放锁时需要判断是否是当前线程持有锁,如果不是throw new IllegalMonitorStateException();如果是通过setExclusiveOwnerThread(null)释放锁,并通过cas的方式将state设置为0。如果线程获取锁失败会将当前线程加入到CLH队列,采用双向链表结构,节点包含线程的引用、等待状态(status>0表示需要被唤醒,为0表示不需要)以及前驱和后继节点的职责。对于获取锁失败的线程会通过循环不断检查节点状态,等待其他线程释放锁,然后去获取锁。 CLH双向链表
-
获取锁失败的线程会被封装成
Node
并加入队列。 -
队列采用 FIFO 策略,但支持条件变量(
Condition
)唤醒。public final void acquire(int arg) { if (!tryAcquire(arg)) acquire(null, arg, false, false, false, 0L); //通过无限循环 (for(;;)) 持续检查当前节点的状态,包括是否为队列头节点、前驱节点状态等。尝试去获取锁。 }
java
public final boolean release(int arg) {
if (tryRelease(arg)) {
signalNext(head);//释放成功后唤醒下一节点
return true;
}
return false;
}
private static void signalNext(Node h) {
Node s;
if (h != null && (s = h.next) != null && s.status != 0) {//判断后继节点是否存在,以及它的状态,确保后继节点 s 的状态 status 不为 0(表示需要被唤醒)。
s.getAndUnsetStatus(WAITING); //取消设置后继节点状态为waiting
LockSupport.unpark(s.waiter); //唤醒后继结点的关联线程,调用此方法会取消对指定线程的阻塞状态,使其有机会重新获得CPU执行权。
}
}
AQS还有一个内部类,ConditionObject,主要用于实现线程的等待/通知机制。

csharp
abstract static class Node { //clh队列
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
}
arduino
/**字段偏移量计算:利用 Unsafe.objectFieldOffset 计算 AbstractQueuedSynchronizer 类中
*/state、head 和 tail 字段的内存偏移量,便于后续通过 CAS 操作高效更新这些字段。
private static final Unsafe U = Unsafe.getUnsafe();
private static final long STATE
= U.objectFieldOffset(AbstractQueuedSynchronizer.class, "state");
private static final long HEAD
= U.objectFieldOffset(AbstractQueuedSynchronizer.class, "head");
private static final long TAIL
= U.objectFieldOffset(AbstractQueuedSynchronizer.class, "tail");
AQS(AbstractQueuedSynchronizer
)是 Java 并发包 (java.util.concurrent.locks
) 的核心同步框架,许多同步工具(如 ReentrantLock
、Semaphore
、CountDownLatch
等)都是基于它实现的。
AQS 的核心思想是:
- 管理一个共享的同步状态(
state
) ,并提供 CAS(Compare-And-Swap) 操作来修改状态。 - 维护一个 CLH 变体的 FIFO 线程等待队列,用于管理获取锁失败的线程。
- 支持独占模式(如
ReentrantLock
)和共享模式(如Semaphore
) 。
java
//独占锁示例
class Mutex implements Lock, java.io.Serializable {
// Our internal helper class
private static class Sync extends AbstractQueuedSynchronizer {
// Acquires the lock if state is zero
public boolean tryAcquire(int acquires) {
assert acquires == 1; // Otherwise unused
if (compareAndSetState(0, 1)) { //比较并交换
setExclusiveOwnerThread(Thread.currentThread()); //设置当前拥有独占访问权限的线程。
return true;
}
return false;
}
// Releases the lock by setting state to zero
protected boolean tryRelease(int releases) {
assert releases == 1; // Otherwise unused
if (!isHeldExclusively()) //判断要释放锁的线程是否是加锁线程
throw new IllegalMonitorStateException();
setExclusiveOwnerThread(null);//释放锁,参数 null 表示没有线程拥有访问权限。
setState(0); //设置state值为0
return true;
}
// Reports whether in locked state
public boolean isLocked() {
return getState() != 0;
}
public boolean isHeldExclusively() { //判断要释放锁的线程是否是加锁线程
// a data race, but safe due to out-of-thin-air guarantees
return getExclusiveOwnerThread() == Thread.currentThread();
}
// Provides a Condition
public Condition newCondition() {
return new ConditionObject();
}
// Deserializes properly
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException {
s.defaultReadObject();
setState(0); // reset to unlocked state
}
}
// The sync object does all the hard work. We just forward to it.
private final Sync sync = new Sync();
public void lock() { sync.acquire(1); } //父类的
public boolean tryLock() { return sync.tryAcquire(1); }//子类的
public void unlock() { sync.release(1); } //父类
public Condition newCondition() { return sync.newCondition(); } //子类
public boolean isLocked() { return sync.isLocked(); }
public boolean isHeldByCurrentThread() {
return sync.isHeldExclusively();
}
public boolean hasQueuedThreads() {
return sync.hasQueuedThreads();
}
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
}