Lock的实现之ReentrantLock详解(3)

总体来讲,acquireQueued就是依靠前驱节点的状态来决定当前线程是否应该处于阻塞状态,如果前驱节点处于cancel状态,则丢弃这些节点,重新构建队列;

Unlock API详解

流程类似lock api相关类的流程,这里讲主要的代码,unlock相对的比较简单

首先 ReentrantLock 调用 Sync的release接口也就是AbstractQueuedSynchronizer的release接口

/** * Releases in exclusive mode. Implemented by unblocking one or * more threads if {@link #tryRelease} returns true. * This method can be used to implement method {@link Lock#unlock}. * * @param arg the release argument. This value is conveyed to * {@link #tryRelease} but is otherwise uninterpreted and * can represent anything you like. * @return the value returned from {@link #tryRelease} */ public final boolean release(int arg) { if (tryRelease(arg)) { Node h = head; if (h != null && h.waitStatus != 0) unparkSuccessor(h); return true; } return false; }

这个时候会先调用Sync的tryRelease,如果返回true,则释放锁成功

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; }

这个接口的作用很简单,如果不是获得锁的线程调用直接抛出异常,否则,如果当前state-releases==0也就是lock已经完全释放,返回true,清除资源;

这个返回free之后,release拿到head节点,进入以下代码:

/** * Wakes up node's successor, if one exists. * * @param node the node */ 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. */ 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); }

这个作用即:当头结点的状态小于0,则将头结点的状态CAS为0,然后通过链表获取下一个节点,如果下一个节点为null或者不符合要求的状态,则从队尾遍历整个链表,直到遍历到离head节点最近的一个节点并且

等待状态符合预期,则将头结点的后继节点置为该节点;

对刚刚筛出来的符合要求的节点唤醒,也就是该节点获得 争夺 锁的权利;

这就是非公平锁的特点:在队列一直等待的线程不一定比后来的线程先获得锁,至此,unlock 已经解释完成;

凌渡冰 目前就职于美团 Do what you like to impact the world.

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/d43128d59cd0ab46213f0d10b1c35f86.html