AQS 小知识

AQS的源码也看了好几遍了,在看代码的过程中发现一些值得注意的点

  1 排他锁第一次进来,不会产生队列,而是直接返回

  2 第二个线程竞争锁,会产生队列,同时header是一个哨兵节点,因为唤醒逻辑是唤醒头结点的下一个节点

  3 什么时候会产生CANCEL状态,注意是doAcquireInterruptibly

private void doAcquireInterruptibly(int arg)
        throws InterruptedException {
        final Node node = addWaiter(Node.EXCLUSIVE);
        boolean failed = true;
        try {
            for (;;) {
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return;
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())//如果是线程中断导致的唤醒,会抛异常,就会走到finally分支
                    throw new InterruptedException();
            }
        } finally {
            if (failed)//只有中断的情况,才有可能跳出上面的自旋,failed==true
                cancelAcquire(node);
        }
    }

  整个类里我只看到这么一处设置CANCELLED

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)
            node.prev = pred = pred.prev;

        // 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.
        if (node == tail && compareAndSetTail(node, pred)) {
            compareAndSetNext(pred, predNext, null);
        } else {
            // If successor needs signal, try to set pred's next-link
            // so it will get one. Otherwise wake it up to propagate.
            int ws;
            if (pred != head &&
                ((ws = pred.waitStatus) == Node.SIGNAL ||
                 (ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
                pred.thread != null) {//如果该node不是头,该节点的pre的状态是signal或者pre通过cas能够设置成signal,那么就可以放心的修改pre的指针了,把该node剔除
                Node next = node.next;
                if (next != null && next.waitStatus <= 0)
                    compareAndSetNext(pred, predNext, next);
            } else {//如果是header,或者cas失败了,那就唤醒它的后继节点
                unparkSuccessor(node);
            }

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

  4 acquireQueued 不会响应中断

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,然后还是会再次自旋,直到获得了锁
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

 5 AQS是一个框架,作为开发者只需要实现这五个方法

  1 protected boolean tryAcquire(int arg) 排他锁

  2 protected boolean tryRelease(int arg) 排他锁

  3 int tryAcquireShared(int arg)共享锁

  4 protected boolean tryReleaseShared(int arg) 共享锁

  5 isHeldExclusively

  这里最特殊的就是 tryAcquireShared ,返回值是int 

  

 

  

posted on 2020-11-09 17:54  MaXianZhe  阅读(90)  评论(0编辑  收藏  举报

导航