美文网首页
AbstractQueuedSynchronizer源码分析第三

AbstractQueuedSynchronizer源码分析第三

作者: 永远的太阳0123 | 来源:发表于2019-01-02 09:04 被阅读0次

    1 AbstractQueuedSynchronizer中的acquireShared方法

        public final void acquireShared(int arg) {
            if (tryAcquireShared(arg) < 0)
                doAcquireShared(arg);
        }
    

    我们可以将acquireShared方法改写成另一种形式。

        public final void acquireShared(int arg) {
            // 尝试获取共享锁
            if (tryAcquireShared(arg) >= 0)
                return;
            else
                doAcquireShared(arg);
        }
    

    1.1 AbstractQueuedSynchronizer中的tryAcquireShared方法

    子类中可以重写tryAcquireShared方法。
    (1)返回值小于0:获取共享锁失败。
    (2)返回值等于0:获取共享锁成功,之后再次尝试获取共享锁一定失败。
    (3)返回值大于0:获取共享锁成功,之后再次尝试获取共享锁可能成功。

        // 尝试获取共享锁
        protected int tryAcquireShared(int arg) {
            throw new UnsupportedOperationException();
        }
    

    1.2 AbstractQueuedSynchronizer中的doAcquireShared方法

        private void doAcquireShared(int arg) {
            // 为当前线程创建节点,并将这个节点插入到同步队列中
            final Node node = addWaiter(Node.SHARED);
            // failed等于true代表当前线程尚未获取共享锁
            // failed等于false代表当前线程已经获取共享锁
            boolean failed = true;
            try {
                // interrupted代表当前线程是否被中断
                boolean interrupted = false;
                // 自旋,直至当前线程已经获取共享锁或抛出异常
                for (;;) {
                    // 获取node节点中的prev字段
                    final Node p = node.predecessor();
                    // 如果node节点中的prev字段等于头节点
                    if (p == head) {
                        // 尝试获取共享锁
                        int r = tryAcquireShared(arg);
                        if (r >= 0) {
                            // 运行到这里,说明当前线程已经获取共享锁
                            setHeadAndPropagate(node, r);
                            // 将原来的头节点中的next字段设为null
                            p.next = null; // help GC
                            if (interrupted)
                                // 恢复当前线程的中断状态
                                selfInterrupt();
                            failed = false;
                            return;
                        }
                    }
                    // 调用shouldParkAfterFailedAcquire方法判断是否应该阻塞当前线程
                    // shouldParkAfterFailedAcquire方法返回true,调用parkAndCheckInterrupt方法阻塞当前线程
                    // shouldParkAfterFailedAcquire方法返回false,继续循环
                    if (shouldParkAfterFailedAcquire(p, node) &&
                        parkAndCheckInterrupt())
                        interrupted = true;
                }
            } finally {
                // 运行到这里,要么当前线程已经获取共享锁,要么抛出异常
                // 如果抛出异常,调用cancelAcquire方法
                if (failed)
                    cancelAcquire(node);
            }
        }
    
    1.2.1 AbstractQueuedSynchronizer中的setHeadAndPropagate方法
        // 传入的propagate是tryAcquireShared方法的返回值
        private void setHeadAndPropagate(Node node, int propagate) {
            Node h = head;
            // 将头节点设为node节点,将node节点中的线程对象设为null,将node节点中的prev字段设为null
            setHead(node);
            if (propagate > 0 || h == null || h.waitStatus < 0 ||
                (h = head) == null || h.waitStatus < 0) {
                Node s = node.next;
                // 如果node节点中的next字段等于null或node节点正在共享模式中等待
                if (s == null || s.isShared())
                    doReleaseShared();
            }
        }
    

    2 AbstractQueuedSynchronizer中的releaseShared方法

        // releaseShared方法的返回值等于tryReleaseShared方法的返回值
        public final boolean releaseShared(int arg) {
            // 尝试释放共享锁
            if (tryReleaseShared(arg)) {
                doReleaseShared();
                return true;
            }
            return false;
        }
    

    2.1 AbstractQueuedSynchronizer中的tryReleaseShared方法

    子类中可以重写tryReleaseShared方法。

        // 尝试释放共享锁
        protected boolean tryReleaseShared(int arg) {
            throw new UnsupportedOperationException();
        }
    

    2.2 AbstractQueuedSynchronizer中的doReleaseShared方法

    setHeadAndPropagate方法和releaseShared方法都可能调用本方法。

        private void doReleaseShared() {
            // 自旋
            for (;;) {
                Node h = head;
                // 如果头节点不等于null并且头节点不等于尾节点
                if (h != null && h != tail) {
                    int ws = h.waitStatus;
                    // 如果头节点中的waitStatus等于-1,尝试将头节点中的waitStatus设为0
                    if (ws == Node.SIGNAL) {
                        if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
                            continue;
                        // 运行到这里,说明成功将头节点中的waitStatus设为0
                        // 唤醒后续节点中的线程对象
                        unparkSuccessor(h);
                    }
                    // 如果头节点中的waitStatus等于0,尝试将头节点中的waitStatus设为-3
                    else if (ws == 0 &&
                             !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
                        continue;
                }
                // 如果头节点保持不变,跳出循环
                if (h == head)
                    break;
            }
        }
    

    3 PROPAGATE

    相关文章

      网友评论

          本文标题:AbstractQueuedSynchronizer源码分析第三

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