美文网首页
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