总结
-
tryRelease方法将当前AQS中锁的状态state-1,如果计算后的state仍然不等于0,意味着锁资源仍然没有被释放,那么不执行后续操作。
-
如果AQS中锁的状态为0,那么获取到当前AQS队列中的头结点。如果这个头结点不为空且是一个条件节点,也就是会对之后的节点产生影响,那么就唤醒一个最近的有效地后继节点的线程。然后结束方法。
unlock
public void unlock() {
sync.release(1);
}
release
public final boolean release(int arg) {
//尝试将释放锁资源
if (tryRelease(arg)) {
// 获取当前AQS中的head节点,
Node h = head;
// 如果当前头结点不为null 并且当前节点的状态不为0,也就意味着他是一个条件节点
if (h != null && h.waitStatus != 0)
// 唤醒一个最近的有效的后继节点的线程
unparkSuccessor(h);
// 结束方法
return true;
}
// 如果尝试释放锁失败那么返回false
return false;
}
tryRelease
protected final boolean tryRelease(int releases) {
// 获取当前锁的状态并-1
int c = getState() - releases;
// 如果当前线程不是同步器中占有锁的线程那么抛出异常
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
// 设置释放状态为false
boolean free = false;
// 如果AQS当前锁的状态-1=0
if (c == 0) {
// 将释放锁的状态设置为true
free = true;
// 将同步器中占有锁的线程设置为null
setExclusiveOwnerThread(null);
}
//将AQS中当前锁的状态设置为0
setState(c);
// 返回true 执行后续操作
return free;
}
unparkSuccessor
private void unparkSuccessor(Node node) {
// 获取当前节点的锁状态
int ws = node.waitStatus;
// 如果当前节点的锁状态小于0
if (ws < 0)
// 通过CAS将当前节点的状态设为0 表示不会再产生后续影响
compareAndSetWaitStatus(node, ws, 0);
// 获取该节点的后继节点
Node s = node.next;
// 如果后继节点为空或者也是一个失效的节点
if (s == null || s.waitStatus > 0) {
//将该后继节点设为null帮助垃圾回收
s = null;
// AQS队列从尾节点开始向前遍历,找到一个有效节点
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
// 将找到的有效的后继节点的线程唤醒
if (s != null)
LockSupport.unpark(s.thread);
}