📚 目录
1. 什么是AQS?
AQS(AbstractQueuedSynchronizer)是Java并发包(java.util.concurrent
)的核心组件,用于构建锁和其他同步器的基础框架。它通过一个FIFO队列管理线程的排队和唤醒机制,提供了独占模式和共享模式的同步功能。
AQS的核心功能:
-
🧩 同步状态管理:通过
state
变量管理锁的状态 -
🛠️ 线程排队:通过FIFO队列管理等待线程
-
🔒 条件支持:支持条件变量(Condition)的实现
AQS的应用:
-
ReentrantLock
-
Semaphore
-
CountDownLatch
-
ReentrantReadWriteLock
2. AQS的核心设计
2.1 同步状态
AQS通过一个volatile int state
变量表示同步状态:
-
在独占模式下,
state
通常表示锁的持有状态(如0表示未锁定,1表示锁定)。 -
在共享模式下,
state
可以表示资源的数量(如信号量的许可数)。
状态操作:
-
getState()
:获取当前状态 -
setState(int newState)
:设置状态 -
compareAndSetState(int expect, int update)
:CAS操作更新状态
2.2 FIFO队列
AQS通过一个双向链表(CLH队列)管理等待线程。每个节点(Node
)包含以下信息:
-
线程引用
-
等待状态(如
CANCELLED
、SIGNAL
) -
前驱和后继节点
队列的作用:
-
公平锁:严格按照FIFO顺序获取锁
-
非公平锁:允许插队获取锁
2.3 独占模式与共享模式
-
独占模式:同一时刻只有一个线程可以获取锁(如
ReentrantLock
)。 -
共享模式:多个线程可以同时获取锁(如
Semaphore
)。
核心方法:
-
tryAcquire(int arg)
:尝试获取独占锁 -
tryRelease(int arg)
:尝试释放独占锁 -
tryAcquireShared(int arg)
:尝试获取共享锁 -
tryReleaseShared(int arg)
:尝试释放共享锁
3. AQS的实现原理
3.1 获取锁
-
调用
acquire(int arg)
方法。 -
尝试获取锁(
tryAcquire
)。-
成功:直接返回
-
失败:将线程加入队列并挂起
-
-
线程被唤醒后,重新尝试获取锁。
源码片段:
public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); }
3.2 释放锁
-
调用
release(int arg)
方法。 -
尝试释放锁(
tryRelease
)。 -
唤醒队列中的下一个线程。
源码片段:
public final boolean release(int arg) { if (tryRelease(arg)) { Node h = head; if (h != null && h.waitStatus != 0) unparkSuccessor(h); return true; } return false; }
3.3 条件队列
AQS通过ConditionObject
实现条件变量,支持线程的等待和唤醒。
-
await()
:线程进入等待状态 -
signal()
:唤醒等待线程
源码片段:
public final void await() throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); Node node = addConditionWaiter(); int savedState = fullyRelease(node); // 挂起线程 while (!isOnSyncQueue(node)) { LockSupport.park(this); if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) break; } // 重新获取锁 if (acquireQueued(node, savedState) && interruptMode != THROW_IE) interruptMode = REINTERRUPT; if (node.nextWaiter != null) unlinkCancelledWaiters(); if (interruptMode != 0) reportInterruptAfterWait(interruptMode); }
4. AQS的应用场景
-
ReentrantLock:基于AQS实现的可重入锁
-
Semaphore:基于AQS实现的信号量
-
CountDownLatch:基于AQS实现的倒计时门闩
-
ReentrantReadWriteLock:基于AQS实现的读写锁
5. AQS的源码分析
AQS的源码非常复杂,但其核心逻辑围绕以下几个部分:
-
状态管理:通过
state
变量实现同步状态的控制。 -
队列管理:通过CLH队列实现线程的排队和唤醒。
-
模板方法:通过
tryAcquire
、tryRelease
等模板方法支持自定义同步器。
源码结构:
-
AbstractQueuedSynchronizer
:AQS的核心类 -
Node
:队列节点类 -
ConditionObject
:条件变量实现类
6. 常见问题与解决方案
-
为什么AQS使用CLH队列?
-
CLH队列是一种无锁队列,适合高并发场景。
-
-
如何实现公平锁和非公平锁?
-
公平锁:严格按照FIFO顺序获取锁
-
非公平锁:允许插队获取锁
-
-
AQS如何支持可重入锁?
-
通过
state
变量记录锁的重入次数。
-
-
AQS的条件变量如何实现?
-
通过
ConditionObject
实现线程的等待和唤醒。
-
7. 面试常见问题
-
AQS的核心设计是什么?
-
同步状态、FIFO队列、独占模式与共享模式。
-
-
AQS如何实现公平锁和非公平锁?
-
公平锁严格按照FIFO顺序获取锁,非公平锁允许插队。
-
-
AQS的条件变量是如何实现的?
-
通过
ConditionObject
实现线程的等待和唤醒。
-
-
AQS的应用场景有哪些?
-
ReentrantLock
、Semaphore
、CountDownLatch
等。
-
📌 小贴士:理解AQS的最佳方式是阅读源码并结合实际应用场景!推荐使用ReentrantLock
和Semaphore
进行实践。需要完整代码示例或深入探讨某个功能,欢迎在评论区留言!
**文章亮点说明**: 1. 采用分层目录结构,支持锚点跳转 2. 提供详细的AQS核心设计和实现原理解析 3. 包含源码片段和常见问题解决方案 4. 使用emoji和视觉元素增强可读性 5. 结合实际应用场景和面试常见问题 符合CSDN技术博客的典型风格,适合作为AQS学习的参考资料。需要补充代码实现细节或扩展某个功能解析,可以随时留言讨论!