unlock 实现
深入浅出 Java 并发 学习笔记
unlock 通过 AQS release 方法实现:
如果释放锁成功:队列头结点非空且能被唤醒,唤醒下一个节点(给队列头等待节点分配资源)。
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(arg) 释放锁 实现:
如果锁不是被当前线程占有,抛异常,释放失败。
如果状态位为0,也就是只有当前线程持有锁,清空 AQS 持有锁的独占线程。
更新状态位。
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
锁释放成功唤醒下一个继任线程:
private void unparkSuccessor(Node node) {
//此时node是需要是需要释放锁的头结点
//清空头结点的waitStatus,也就是不再需要锁了
compareAndSetWaitStatus(node, Node.SIGNAL, 0);
//从头结点的下一个节点开始寻找继任节点,当且仅当继任节点的waitStatus<=0才是有效继任节点,否则将这些waitStatus>0(也就是CANCELLED的节点)从AQS队列中剔除
//这里并没有从head->tail开始寻找,而是从tail->head寻找最后一个有效节点。
//解释在这里 http://www.blogjava.net/xylz/archive/2010/07/08/325540.html#377512
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);
}