美文网首页
ReentrantLock(3) —— 非公平模式解锁流程

ReentrantLock(3) —— 非公平模式解锁流程

作者: 若琳丶 | 来源:发表于2019-11-07 23:46 被阅读0次

    一、解锁流程源码解读

    解锁的源码相对简单,源码如下:

    public void unlock() {
        sync.release(1);  
    }
    
    public final boolean release(int arg) {
        if (tryRelease(arg)) { //释放锁(state-1),若释放后锁可被其他线程获取(state=0),返回true
            Node h = head;
            //当前队列不为空且头结点状态不为初始化状态(0)   
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);  //唤醒同步队列中被阻塞的线程
            return true;
        }
        return false;
    }
    

    正确找到sync的实现类,找到真正的入口方法,主要内容都在一个if语句中,先看下判断条件tryRelease方法

    protected final boolean tryRelease(int releases) {
        int c = getState() - releases; //计算待更新的state值
        if (Thread.currentThread() != getExclusiveOwnerThread())
            throw new IllegalMonitorStateException();
        boolean free = false;
        if (c == 0) { //待更新的state值为0,说明持有锁的线程未重入,一旦释放锁其他线程将能获取
            free = true; 
            setExclusiveOwnerThread(null);//清除锁的持有线程标记
        }
        setState(c);//更新state值
        return free;
    }
    

    tryRelease其实只是将线程持有锁的次数减1,即将state值减1,若减少后线程将完全释放锁(state值为0),则该方法将返回true,否则返回false。由于执行该方法的线程必然持有锁,故该方法不需要任何同步操作。若当前线程已经完全释放锁,即锁可被其他线程使用,则还应该唤醒后续等待线程。不过在此之前需要进行两个条件的判断:

    • h!=null是为了防止队列为空,即没有任何线程处于等待队列中,那么也就不需要进行唤醒的操作
    • h.waitStatus != 0是为了防止队列中虽有线程,但该线程还未阻塞,由前面的分析知,线程在阻塞自己前必须设置前驱结点的状态为SIGNAL,否则它不会阻塞自己。

    接下来就是唤醒线程的操作,unparkSuccessor(h)源码如下

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

    一般情况下只要唤醒后继结点的线程就行了,但是后继结点可能已经取消等待,所以从队列尾部往前回溯,找到离头结点最近的正常结点,并唤醒其线程。

    二、解锁流程源码总结


    解锁流程

    如果有什么地方描述的错误或者缺失,请在下方留言,大家一起交流,一起学习,一起成长~
    下一节:ReentrantLock (四) —— 公平锁相比非公平锁

    相关文章

      网友评论

          本文标题:ReentrantLock(3) —— 非公平模式解锁流程

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