上一篇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 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(); } 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 ) { 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 private void unparkSuccessor (Node node) { int ws = node.waitStatus; if (ws < 0 ) compareAndSetWaitStatus(node, ws, 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); }
至此,可以看到Reentrant
的整个lock()
和unlock()
过程,当节点acquire
成功时,置为头节点,同时其他节点也在acquire
,得不到竞态资源(state)就入队自旋等待,直到持有资源的头节点释放,并唤醒其后续节点。