AQS系列之AbstractQueuedSynchronizer基础分析
AQS系列之以排斥锁分析
AQS系列之以排斥锁分析
一、获取资源
1. 获取资源acquire
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
本方法是获取资源的入口,详细的方法介绍在后文里进行,这里主要说明一个大流程。
- 尝试获取资源,成功则结束
- 获取资源失败,新建节点插入队列
- 在队列里排队并获取资源
- 如果等待过程中出现线程中断,则中断自身
可以看到以下几点:
(1) 首先就是一次资源获取的尝试,具体尝试逻辑由各实现类实现,失败再加入队列
(2) 该方法不响应中断,如果在等待过程线程被中断,线程不会响应,只会在等待结束后中断重新自身
2. 加入队列addWaiter
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
Node pred = tail;
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
//失败后循环自旋尝试
enq(node);
return node;
}
private Node enq(final Node node) {
for (;;) {
Node t = tail;
//一个特殊场景,没有初始化,对头尾指针节点进行初始化
if (t == null) {
// Must initialize
if (compareAndSetHead(new Node()))
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
本方法用于线程节点入队,入队逻辑也不复杂,初始化一个排斥模式的节点加入到队列尾部,tail指向该节点。
本方法先进行一次快速尝试,失败后在一个循环中自旋尝试,这种实现模式非常经典,很多JDK并发包的源码都是这么实现的。后续AQS逻辑里也能继续看到这种方式。
3. 排队获取资源acquireQueued
final boolean acqui