title:(二)Lock.unlock()分析
date:2017年11月12日19:32:35
来看下unlock()方法
public void unlock() {
sync.release(1);
}
unlock()是解锁函数,它是通过AQS的release()函数来实现的。
在这里,“1”的含义和“获取锁的函数acquire(1)的含义”一样,它是设置“释放锁的状态”的参数。由于ReentantLock独占锁是可重入的,所以对于同一个线程,每释放锁一次,锁的状态-1。
release()
release()方法依然是AQS实现的。
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
release()会先调用tryRelease()来尝试释放当前线程锁持有的锁。成功的话,则唤醒后继等待线程,并返回true。否则,直接返回false。
tryRelease()方法
tryRelease()方法是Sync实现,而且NotFairSync和FairSync都没有重写这个方法,这意味着公平锁和非公平锁的解锁方法是完全一样的。
protected final boolean tryRelease(int releases) { // c是本次释放锁之后的状态 int c = getState() - releases; //如果当前线程不是持有锁的线程,则直接抛出异常。 if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; //如果状态为0,已经被当前线程彻底释放,则设置锁的持有者为null,即锁是可获取状态。 if (c == 0) { free = true; setExclusiveOwnerThread(null); } setState(c); return free; }
- getExclusiveOwnerThread(),setExclusiveOwnerThread()
这两个方法都是由AQS的父类AbstractOwnableSynchronizer实现的。
public abstract class AbstractOwnableSynchronizer implements java.io.Serializable { // “锁”的持有线程 private transient Thread exclusiveOwnerThread; // 设置“锁的持有线程”为t protected final void setExclusiveOwnerThread(Thread t) { exclusiveOwnerThread = t; } // 获取“锁的持有线程” protected final Thread getExclusiveOwnerThread() { return exclusiveOwnerThread; } ... }
unparkSuccessor()
在release()中“当前线程”释放锁成功的话,会唤醒当前线程的后继线程。
根据CLH队列的FIFO规则,“当前线程”(即已经获取锁的线程)肯定是head;如果CLH队列非空的话,则唤醒锁的下一个等待线程。private void unparkSuccessor(Node node) { /* * If status is negative (i.e., possibly needing signal) try * to clear in anticipation of signalling. It is OK if this * fails or if status is changed by waiting thread. */ // 获取当前线程的状态 int ws = node.waitStatus; if (ws < 0) compareAndSetWaitStatus(node, ws, 0); /* * Thread to unpark is held in successor, which is normally * just the next node. But if cancelled or apparently null, * traverse backwards from tail to find the actual * non-cancelled successor. */ //获取当前节点的“有效的后继节点”,无效的话,则通过for循环进行获取。 // 这里的有效,是指“后继节点对应的线程状态<=0” 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); }
unparkSuccessor()的作用是“唤醒当前线程的后继线程”。后继线程被唤醒之后,就可以获取该锁并恢复运行了。