尝试释放此锁。如果当前线程是此锁的持有者,则保留计数将减少。 如果保持计数现在为零,则释放锁定。 如果当前线程不是此锁的持有者,则抛出IllegalMonitorStateException。
## ReentrantLock public void unlock() { sync.release(1); }sync.release(1) 调用的是AbstractQueuedSynchronizer中的release方法
## AbstractQueuedSynchronizer 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)方法
tryRelease(arg)该方法调用的是ReentrantLock中
protected final boolean tryRelease(int releases) { // 获取当前锁持有的线程数量和需要释放的值进行相减 int c = getState() - releases; // 如果当前线程不是锁占有的线程抛出异常 if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; // 如果此时c = 0就意味着state = 0,当前锁没有被任意线程占有 // 将当前所的占有线程设置为空 if (c == 0) { free = true; setExclusiveOwnerThread(null); } // 设置state的值为 0 setState(c); return free; } 如果头节点不为空,并且waitStatus != 0,唤醒后续节点如果存在的话。
这里的判断条件为什么是h != null && h.waitStatus != 0?
因为h == null的话,Head还没初始化。初始情况下,head == null,第一个节点入队,Head会被初始化一个虚拟节点。所以说,这里如果还没来得及入队,就会出现head == null 的情况。
h != null && waitStatus == 0 表明后继节点对应的线程仍在运行中,不需要唤醒
h != null && waitStatus < 0 表明后继节点可能被阻塞了,需要唤醒
private void unparkSuccessor(Node node) { // 获取头结点waitStatus int ws = node.waitStatus; if (ws < 0) compareAndSetWaitStatus(node, ws, 0); // 获取当前节点的下一个节点 Node s = node.next; //如果下个节点是null或者下个节点被cancelled,就找到队列最开始的非cancelled的节点 if (s == null || s.waitStatus > 0) { s = null; // 就从尾部节点开始找往前遍历,找到队列中第一个waitStatus<0的节点。 for (Node t = tail; t != null && t != node; t = t.prev) if (t.waitStatus <= 0) s = t; } // 如果当前节点的下个节点不为空,而且状态<=0,就把当前节点唤醒 if (s != null) LockSupport.unpark(s.thread); } 为什么要从后往前找第一个非Cancelled的节点呢?
看一下addWaiter方法
我们从这里可以看到,节点入队并不是原子操作,也就是说,node.prev = pred, compareAndSetTail(pred, node) 这两个地方可以看作Tail入队的原子操作,但是此时pred.next = node;还没执行,如果这个时候执行了unparkSuccessor方法,就没办法从前往后找了,所以需要从后往前找。还有一点原因,在产生CANCELLED状态节点的时候,先断开的是Next指针,Prev指针并未断开,因此也是必须要从后往前遍历才能够遍历完全部的Node。
所以,如果是从前往后找,由于极端情况下入队的非原子操作和CANCELLED节点产生过程中断开Next指针的操作,可能会导致无法遍历所有的节点。所以,唤醒对应的线程后,对应的线程就会继续往下执行。
由于篇幅较长公平锁的实现在下一篇的博客中讲述,谢谢大家的关注和支持!有问题希望大家指出,共同进步!!!