上文阐述了什么是AQS,本文来对AQS进行一个补充:
首先先来了解一下,CLH队列变体中的结点结构
waitStatus 状态分为以下几种:
-
CANCELLED(1):取消状态,标志该线程不再参与锁的争抢
-
SIGNAL(-1):标记后继节点的线程需要被阻塞
-
CONDITION(-2):同步阻塞状态,类似调用了Object.wait()
-
PROPAGATE(-3):共享模式,同步状态可传播状态
-
0:初始状态
一个结点是如何加入到CLH队列的
如果当前队列为空的话,虚拟化出一个新的 Node 头节点,这时队列中只有一个元素,为了保证 AQS 队列结构的完整性,会将尾节点指向头节点。
如果队列不为空的话,首先会让新节点prev指针指向当前队列的队尾,再将tail指针指向新结点,最后将新节点的前驱结点的next指针指向新结点。
下面是底层源码:
private Node enq(final Node node) {
for (; ; ) {
Node t = tail;
if (t == null) {
// 虚拟化一个空Node, 并将head指向空Node
if (compareAndSetHead(new Node()))
// 将尾节点等于头节点
tail = head;
} else {
// node上一条指向尾节点
node.prev = t;
// 设置node为尾节点
if (compareAndSetTail(t, node)) {
// 设置原尾节点的下一条指向node
t.next = node;
return t;
}
}
}
}
介绍一下 LockSupport
在AQS中,队列中线程的阻塞唤醒都是通过LockSupport实现的。
LockSupport类,是用来创建锁和其他同步类的基本线程阻塞原语,核心方法有两个:
-
park():阻塞当前调用线程。
-
unpark():唤醒指定线程。