AQS源码解析(3)

上一篇AQS源码解析(2),学习了ReentrantLock的加锁过程,对照地来看一下如何释放锁。与加锁有一些不同的地方是,释放时直接就release(1),这是在AQS中实现的,不像加锁时在Sync的子类中才实现。

1
2
3
4
5
6
7
8
9
10
11
public class ReentrantLock implements Lock, java.io.Serializable {
private final Sync sync;

public void unlock() {
sync.release(1);
}

abstract static class Sync extends AbstractQueuedSynchronizer {
protected final boolean tryRelease(int releases) {} // 见下文
}
}

核心方法有两个tryRelease()unparkSuccessor(),看过加锁实现,应该也能猜到,tryRelease应该是在子类中才实现的,果不其然,AQS里只是定义,但不像加锁那样分为公平/非公平各自实现。而后者从名字能猜到,是要唤醒链表中的后续节点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/** AbstractQueuedSynchronizer.java **/
public final boolean release(int arg) {
if (tryRelease(arg)) { // 尝试释放资源
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h); // 唤醒头节点的后续节点
return true;
}
return false;
}

protected boolean tryRelease(int arg) {
throw new UnsupportedOperationException();
}

/** ReentrantLock#Sync.java **/
abstract static class Sync extends AbstractQueuedSynchronizer {
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
// 当前线程不是独占的,抛异常
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) { // 之前acquire(1),现在releases(1)
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
}

ReentrantLock为例,lock()本质上就是acquire(1)的过程,在unlock()时只需释放掉这拿到的1个状态资源,接着分析上一篇中遗留的unparkSuccessor()方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/** AbstractQueuedSynchronizer.java **/
private void unparkSuccessor(Node node) {
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0); // 节点置为无状态

// 找到后续节点,如果是null或者是CANCELLED状态的话,从尾节点向前找
Node s = node.next;
if (s == null || s.waitStatus > 0) {
s = null;
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
if (s != null)
LockSupport.unpark(s.thread);
}

至此,可以看到Reentrant的整个lock()unlock()过程,当节点acquire成功时,置为头节点,同时其他节点也在acquire,得不到竞态资源(state)就入队自旋等待,直到持有资源的头节点释放,并唤醒其后续节点。