@@ -908,21 +908,34 @@ public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchron
908
908
}
909
909
```
910
910
911
- AQS 为构建锁和同步器提供了一些通用功能的实现,因此,使用 AQS 能简单且高效地构造出应用广泛的大量的同步器,比如我们提到的 `ReentrantLock `,`Semaphore `,其他的诸如 `ReentrantReadWriteLock `,`SynchronousQueue `等等皆是基于 AQS 的。
911
+ AQS 解决了开发者在实现同步器时的复杂性问题。它提供了一个通用框架,用于实现各种同步器,例如 ** 可重入锁** (`ReentrantLock `)、** 信号量** (`Semaphore `)和 ** 倒计时器** (`CountDownLatch `)。通过封装底层的线程同步机制,AQS 将复杂的线程管理逻辑隐藏起来,使开发者只需专注于具体的同步逻辑。
912
+
913
+ 简单来说,AQS 是一个抽象类,为同步器提供了通用的 ** 执行框架** 。它定义了 ** 资源获取和释放的通用流程** ,而具体的资源获取逻辑则由具体同步器通过重写模板方法来实现。 因此,可以将 AQS 看作是同步器的 ** 基础“底座”** ,而同步器则是基于 AQS 实现的 ** 具体“应用”** 。
912
914
913
915
### ⭐️AQS 的原理是什么?
914
916
915
- AQS 核心思想是,如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,那么就需要一套线程阻塞等待以及被唤醒时锁分配的机制,这个机制 AQS 是用 ** CLH 队列锁** 实现的,即将暂时获取不到锁的线程加入到队列中。
917
+ AQS 核心思想是,如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,那么就需要一套线程阻塞等待以及被唤醒时锁分配的机制,这个机制 AQS 是基于 ** CLH 锁** (Craig , Landin , and Hagersten locks) 进一步优化实现的。
918
+
919
+ ** CLH 锁** 对自旋锁进行了改进,是基于单链表的自旋锁。在多线程场景下,会将请求获取锁的线程组织成一个单向队列,每个等待的线程会通过自旋访问前一个线程节点的状态,前一个节点释放锁之后,当前节点才可以获取锁。** CLH 锁** 的队列结构如下图所示。
920
+
921
+ ! [CLH 锁的队列结构](https: // oss.javaguide.cn/github/javaguide/open-source-project/clh-lock-queue-structure.png)
922
+
923
+ AQS 中使用的 ** 等待队列** 是 CLH 锁队列的变体(接下来简称为 CLH 变体队列)。
924
+
925
+ AQS 的 CLH 变体队列是一个双向队列,会暂时获取不到锁的线程将被加入到该队列中,CLH 变体队列和原本的 CLH 锁队列的区别主要有两点:
926
+
927
+ - 由 ** 自旋** 优化为 ** 自旋 + 阻塞** :自旋操作的性能很高,但大量的自旋操作比较占用 CPU 资源,因此在 CLH 变体队列中会先通过自旋尝试获取锁,如果失败再进行阻塞等待。
928
+ - 由 ** 单向队列** 优化为 ** 双向队列** :在 CLH 变体队列中,会对等待的线程进行阻塞操作,当队列前边的线程释放锁之后,需要对后边的线程进行唤醒,因此增加了 `next` 指针,成为了双向队列。
916
929
917
- CLH ( Craig , Landin ,and Hagersten ) 队列是一个虚拟的双向队列(虚拟的双向队列即不存在队列实例,仅存在结点之间的关联关系)。 AQS 是将每条请求共享资源的线程封装成一个 CLH 锁队列的一个结点 (Node )来实现锁的分配。在 CLH 同步队列中 ,一个节点表示一个线程,它保存着线程的引用(thread)、 当前节点在队列中的状态(waitStatus)、前驱节点(prev)、后继节点(next)。
930
+ AQS 将每条请求共享资源的线程封装成一个 CLH 变体队列的一个结点 (Node )来实现锁的分配。在 CLH 变体队列中 ,一个节点表示一个线程,它保存着线程的引用(thread)、 当前节点在队列中的状态(waitStatus)、前驱节点(prev)、后继节点(next)。
918
931
919
- CLH 队列结构如下图所示 :
932
+ AQS 中的 CLH 变体队列结构如下图所示 :
920
933
921
- ! [](https: // oss.javaguide.cn/p3-juejin/40cb932a64694262993907ebda6a0bfe~tplv-k3u1fbpfcp-zoom-1 .png)
934
+ ! [CLH 变体队列结构 ](https: // oss.javaguide.cn/github/javaguide/java/concurrent/clh-queue-structure-bianti .png)
922
935
923
- AQS (`AbstractQueuedSynchronizer `)的核心原理图(图源[ Java 并发之 AQS 详解](https : // www.cnblogs.com/waterystone/p/4920797.html))如下 :
936
+ AQS (`AbstractQueuedSynchronizer `)的核心原理图:
924
937
925
- ! [](https: // oss.javaguide.cn/github/javaguide/java/CLH .png)
938
+ ! [CLH 变体队列 ](https: // oss.javaguide.cn/github/javaguide/java/concurrent/clh-queue-state .png)
926
939
927
940
AQS 使用 ** int 成员变量 `state` 表示同步状态** ,通过内置的 ** 线程等待队列** 来完成获取资源线程的排队工作。
928
941
0 commit comments