1、AbstractQueuedSynchronizer
头节点:获取同步状态成功的节点
尾节点:线程无法获取到同步状态,而被构造成节点,加入到同步队列。
加入队列必须保证线程安全:
compareAndSetTail(Node expect, Node update);
2、独占式同步
1)获取同步状态
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
首先tryAquire(int arg)方法获取同步状态,若获取失败,则构造同步节点(独占式节点,Node.EXCLUSIVE,即一个时刻只能有一个线程成功获取同步状态),
然后加入同步队列的尾部(addWaitor(Node node)),
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;
}
}
}
}
最后以“死循环”方式获取同步状态(acquireQueued(Node node, int arg)),若获取不到则线程一直阻塞。
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
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);
}
}
只有头节点才能获取同步状态,头节点成功获取同步状态之后,释放自己的同步状态,唤醒其后继节点。
节点自旋:每个节点自省观察前驱节点是否是头节点,若是,则获取到同步状态,自动退出自旋过程。
2)释放同步状态
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
同步器释放同步状态(tryRelease(int arg)),并唤醒等待线程(unparkSuccessor方法使用LockSupport来唤醒处于等待状态的线程)。
3)总结
进队列:获取同步状态时,获取失败的线程会加入到同步队列中,并进行自旋;
出队列:头节点成功获取同步状态,然后释放同步状态,唤醒后继节点。
2、共享式同步状态
共享式与独占式最主要区别:同一时刻能否有多个线程获取到同步状态。
1)获取同步状态
public final void acquireShared(int arg) {
if (tryAcquireShared(arg) < 0)
doAcquireShared(arg);
}
private void doAcquireShared(int arg) {
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head) {
int r = tryAcquireShared(arg);
if (r >= 0) {
setHeadAndPropagate(node, r);
p.next = null; // help GC
if (interrupted)
selfInterrupt();
failed = false;
return;
}
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
同步器尝试获取同步状态,tryAcquireShared(int arg)返回int类型,当返回值大于0时,表示能够获取到同步状态;
返回值小于0时,进入doAcquireShared(int arg)自旋。
2)释放同步状态
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
private void doReleaseShared() {
for (;;) {
Node h = head;
if (h != null && h != tail) {
int ws = h.waitStatus;
if (ws == Node.SIGNAL) {
if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
continue; // loop to recheck cases
unparkSuccessor(h);
}
else if (ws == 0 &&
!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
continue; // loop on failed CAS
}
if (h == head) // loop if head changed
break;
}
}
释放同步状态后,唤醒后续处于等待状态的节点,对于同时释放来自多个线程的同步状态,一般通过循环和CAS来保证。