美文网首页
aqs-队列和同步状态

aqs-队列和同步状态

作者: 兴浩 | 来源:发表于2018-06-16 21:54 被阅读6次

    参考:
    http://9056c4f4.wiz03.com/share/s/2glIjQ0JcAZG22OnBj0NaD4u3LNmdz1RAkzX2dbQHr00enD2

    上面文章基本涵盖了很多的基本数据结果概念

    1.Node数据结构
    2.同步队列结构图

    重点关注acquire方法模板中,添加Node的实现

        public final void acquire(int arg) {
            if (!tryAcquire(arg) &&
                acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
                selfInterrupt();
        }
    

    1. addWaiter

        /**
         * Creates and enqueues node for current thread and given mode.
         *
         * @param mode Node.EXCLUSIVE for exclusive, Node.SHARED for shared
         * @return the new node
         */
        private Node addWaiter(Node mode) {
            Node node = new Node(Thread.currentThread(), mode);
            // Try the fast path of enq; backup to full enq on failure
            Node pred = tail;
            if (pred != null) {
                node.prev = pred;
                if (compareAndSetTail(pred, node)) {
                    pred.next = node;
                    return node;
                }
            }
            enq(node);
            return node;
        }
    
        /**
         * Inserts node into queue, initializing if necessary. See picture above.
         * @param node the node to insert
         * @return node's predecessor
         */
        private Node enq(final Node node) {
            for (;;) {
                Node t = tail;
                if (t == null) { // Must initialize
                    if (compareAndSetHead(new Node()))
                        tail = head;
                } else {
                    node.prev = t;
                    if (compareAndSetTail(t, node)) {
                        t.next = node;
                        return t;
                    }
                }
            }
        }
    

    addWaiter方法和enq有部分代码是比较像的,
    初始化时,会调用enq方法,初始化head和tail,并将添加的Node节点添加到队尾
    如果有队尾(即有节点),则快速结束

    2. acquireQueued方法

    2.1出列

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

    参考图片:


    这里完成了一个出列的过程

    2.2 同步状态的线程阻塞
    parkAndCheckInterrupt在入列的时候,使用LockSupport阻塞线程

        private final boolean parkAndCheckInterrupt() {
            LockSupport.park(this);
            return Thread.interrupted();
        }
    

    3.锁释放

    锁释放也是先调用tryRelease,将state重置为0,然后调用unparkSuccessor方法

        public final boolean release(int arg) {
            if (tryRelease(arg)) {
                Node h = head;
                if (h != null && h.waitStatus != 0)
                    unparkSuccessor(h);
                return true;
            }
            return false;
        }
    

    unparkSuccessor方法查找当前node的next节点,并调用LockSupport的unpark方法,唤醒线程

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

    参考:

    【死磕Java并发】—–J.U.C之AQS:CLH同步队列

    【死磕Java并发】—–J.U.C之AQS:同步状态的获取与释放

    相关文章

      网友评论

          本文标题:aqs-队列和同步状态

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