美文网首页
AQS源码解析(3)cancelAcquire

AQS源码解析(3)cancelAcquire

作者: 三斤牛肉 | 来源:发表于2021-01-07 14:15 被阅读0次

先看之前的代码:

final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

之前说过当node获取到锁后会跳出死循环,然后会进入fianlly中,当failed为true时进入cancelAcquire,看代码,除了初始化的时候其实没有地方显式的设为true,所以只有异常情况下会进入。
注:在doAcquireInterruptibly中会显式跑出异常,doAcquireInterruptibly和acquireQueued代码差不多。
再看cancelAcquire代码

private void cancelAcquire(Node node) {
        // Ignore if node doesn't exist
        if (node == null)
            return;

        node.thread = null;

        // Skip cancelled predecessors
        Node pred = node.prev;
        while (pred.waitStatus > 0) //waitStatus>0表示该节点是被取消的节点,则会跳过,理论上来说除了前面的异常,不应该有被取消的节点  
            node.prev = pred = pred.prev;//将node的前置设为第一个waitStatus<=0(正常等待)的节点

        // predNext is the apparent node to unsplice. CASes below will
        // fail if not, in which case, we lost race vs another cancel
        // or signal, so no further action is necessary.
        Node predNext = pred.next;

        // Can use unconditional write instead of CAS here.
        // After this atomic step, other Nodes can skip past us.
        // Before, we are free of interference from other threads.
        node.waitStatus = Node.CANCELLED;

        // If we are the tail, remove ourselves.
        //如果当前节点是队尾,则移除掉,将队尾指向之前的pred,也就是第一个正常的节点
        if (node == tail && compareAndSetTail(node, pred)) {
            //再将pred的next设为null,表示是队尾
            compareAndSetNext(pred, predNext, null);
        } else {//进入else说明node不是队尾(或者是队尾但是cas队尾失败(其实结果也不是队尾,因为被别的线程抢先了))
            // If successor needs signal, try to set pred's next-link
            // so it will get one. Otherwise wake it up to propagate.
            int ws;
            
            //如果前置节点不是head,且ws==-1(如果不是-1则强制cas成-1)
            //这里的cas ws没看懂
            if (pred != head &&
                ((ws = pred.waitStatus) == Node.SIGNAL ||
                 (ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
                pred.thread != null) {
                Node next = node.next;
              //将node之后的节点链到pred上
                if (next != null && next.waitStatus <= 0)
                    compareAndSetNext(pred, predNext, next);
            } else {//如果是头节点就unpark线程
                unparkSuccessor(node);
            }

            node.next = node; // help GC
        }
    }

相关文章

网友评论

      本文标题:AQS源码解析(3)cancelAcquire

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