面试知识库
极高 困难

AQS原理#

一句话答案#

AQS 是 Java 并发包的骨架,核心:volatile int state(资源状态)+ CLH 队列(等待线程),ReentrantLock/Semaphore/CountDownLatch 都基于它。

核心要点

AQS 是 Java 并发包的骨架,ReentrantLock、Semaphore、CountDownLatch、CyclicBarrier 都基于它实现。

核心设计:

AQS 的两个核心结构:
1. volatile int state  → 共享资源的状态(锁计数/许可数等)
2. CLH 队列(双向链表)→ 等待获取资源的线程队列
plaintext

CLH 队列(FIFO 虚拟队列):

Head(哑节点)← → Node(thread1, CANCELLED) ← → Node(thread2, SIGNAL) ← → Tail

                                                  等待被唤醒的线程
plaintext

每个 Node 的状态(waitStatus):

  • SIGNAL(-1):后继节点需要被唤醒
  • CANCELLED(1):线程已取消等待
  • CONDITION(-2):在条件队列中等待
  • PROPAGATE(-3):共享模式下传播唤醒

独占锁的获取流程(以 ReentrantLock 为例):

1. tryAcquire():CAS 尝试将 state 从 0 改为 1
   ├─ 成功 → 获锁,直接返回
   └─ 失败 → 当前线程封装为 Node 加入 CLH 队列尾部

2. 进入 acquireQueued() 自旋:
   ├─ 前驱节点是 Head?→ 再次 tryAcquire()(此时有机会获锁)
   │   ├─ 成功 → 出队,成为新的 Head,返回
   │   └─ 失败 → 将前驱 waitStatus 设为 SIGNAL,然后 park() 挂起
   └─ 等待前驱节点 unpark() 唤醒 → 重复自旋
   
3. 释放锁(unlock):
   tryRelease() 将 state 改回 0
   unpark(head.next.thread) 唤醒队列中第一个等待线程
plaintext

共享模式(Semaphore / CountDownLatch):

  • 多个线程可以同时持有(state > 0),state 减到 0 时后续线程等待
  • acquireShared() / releaseShared()
面试回答(2分钟版)

AQS 全称 AbstractQueuedSynchronizer,是 Java 并发包的核心骨架,ReentrantLock、Semaphore、CountDownLatch 等都基于它实现。AQS 内部维护两个关键结构:一个 volatile int state 表示资源状态,一个 CLH 双向链表队列存放等待获取资源的线程节点。以 ReentrantLock 为例,线程调用 lock 时先通过 CAS 尝试将 state 从 0 改为 1,成功则直接获锁;失败则把当前线程封装成 Node 加入 CLH 队列尾部,然后检查前驱节点是否为 Head,是的话再尝试一次获锁,仍然失败就将前驱 waitStatus 设为 SIGNAL 并调用 LockSupport.park() 挂起自己。释放锁时将 state 置回 0,然后 unpark 唤醒队列中下一个等待线程。公平锁和非公平锁的区别在于:非公平锁上来直接 CAS 抢,失败才排队;公平锁先检查队列中是否有等待线程,有则老老实实排队。state 在不同实现中含义不同,ReentrantLock 中是重入计数,Semaphore 中是许可数。

追问与易错

追问方向:

  • “公平锁和非公平锁在 AQS 中怎么实现的?”→ 公平锁先看队列是否有等待,非公平直接 CAS 抢
  • AQS 的 state 在不同实现中表示什么?(ReentrantLock→重入数,Semaphore→许可数,CountDownLatch→计数)
  • “独占模式和共享模式的区别?”→ 独占 acquire/release,共享 acquireShared/releaseShared

易错点:

  • ❌ “AQS 用的是 CAS 自旋”——入队后是 park 阻塞,不是一直自旋
  • ❌ 混淆 CLH 队列和 Condition 队列——CLH 是同步队列,Condition 是等待队列