tail;
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
//尾节点为空或则CAS失败执行enq
enq(node);
return node;
}
private Node enq(final Node node) {
//失败重试
for (;;) {
Node t = tail;
//没有尾节点 则CAS设置头节点(头尾节点为一个节点),否则CAS设置尾节点
if (t == null) { // Must initialize
if (compareAndSetHead(new Node()))
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
enq
方法主要以自旋(中途不会进入等待模式)去CAS设置尾节点,如果AQS中没有节点则头尾节点为同一节点
由于添加到尾节点存在竞争,因此需要用CAS去替换尾节点
acquireQueued
acquireQueued
方法主要用于AQS队列中的节点来自旋获取同步状态,在这个自旋中并不是一直执行的,而是会被park进入等待
final boolean acquireQueued(final Node node, int arg) {
//记录是否失败
boolean failed = true;
try {
//记录是否中断过
boolean interrupted = false;
//失败重试
for (;;) {
//p 前驱节点
final Node p = node.predecessor();
//如果前驱节点为头节点,并尝试获取同步状态成功则返回
if (p == head && tryAcquire(arg)) {
//设置头节点
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
//失败则设置下标记然后进入等待检查中断
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
//如果失败则取消获取
if (failed)
cancelAcquire(node);
}
}
在尝试获取同步状态前有个条件p == head && tryAcquire(arg)
:前驱节点是头节点
因此AQS中的节点获取状态是FIFO的
但即使满足前驱节点是头节点,并不一定就能获取同步状态成功,因为还未加入AQS的线程也可能尝试获取同步状态,以此来实现非公平锁
那如何实现公平锁呢?
在尝试获取同步状态前都加上这个条件就行了呗!
再来看看