美文网首页
ReentrantLock中的unlock流程

ReentrantLock中的unlock流程

作者: None_Ling | 来源:发表于2016-07-08 20:55 被阅读84次

    在调用到ReentrantLock的unlock方法的时候,无论公平锁与非公平锁都会调用到sync.release(1)方法。

    Sync.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}
     */
    

    从一个独占的模式中退出。如果tryRelease方法返回true的话,则通过unblock一个或者多个线程来实现。这个方法通常用来实现Lock.unlock函数。

    而代码如下

     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方法,如果返回true的话,说明解锁成功,那么则会将当前的head节点进行解锁,接着判断waitStatus不为0,说明当前头节点处于非运行状态,则会调用unparkSuccessor,将头节点传入,而头节点的Thread也因此被唤醒。

    tryRelease方法解析

    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;
        }
    
    1. 判断当前的线程是否是占用锁的线程,如果不是的话,那么抛出非法异常
    2. 否则的话,则判断减少releases之后的值是否为0,如果为0的话,说明目前锁都已经被释放了,则free标识为true,说明当前锁处于空闲状态,并且将当前锁占有线程置空
    3. 设置当前的锁状态,并且返回当前锁是否是空闲的

    unparkSuccessor解析

    该方法的作用是唤醒一个这个节点的后继,也就是head->next。

    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);
    }
    
    1. 首先判断当前节点的waitStatus是否小于0,如果小于0的话,说明当前的状态都是SINGNAL等状态,则通过CAS操作将当前节点的ws变量清空
    2. 获取当前节点的next节点,如果next节点为空或者waitStatus大于0的话,那么说明next节点不合法,则会从后往前遍历,找到最前面一个waitStatus<=0的节点,只有这种节点的线程代表着被阻塞了,那么则调用LockSupport.unpark(s.thread)将该节点阻塞的线程释放,继续执行。

    相关文章

      网友评论

          本文标题:ReentrantLock中的unlock流程

          本文链接:https://www.haomeiwen.com/subject/ihjrjttx.html