关于java:AbstractQueuedSynchronizer那些事儿五-release系列

概述

跟之前的思路一样咱们也采纳自顶向下的办法来剖析release的具体实现

独占模式:release办法

这个办法就是独占模式下的开释锁的入口办法,能够看到十分的简略就是在开释锁胜利当前,要唤醒head节点的无效后继节点来竞争锁,这里有个细节就是waitStatus != 0,我猜想是为了避免多个线程同时调用release办法,且都tryRelease胜利了,避免屡次同时唤醒head节点的后继节点,从而导致后继节点的下次park间接返回?因为在unparkSuccessor中会把head节点的waitStatus赋值为0,然而我感觉仿佛这段代码也不是线程平安的,如果线程A与线程B同时进入,它们同时看到的head节点的waitStatus为SIGNAL,而后它们就会同时进入unparkSuccessor办法,那么此处的waitStatus != 0意义何在呢?

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

共享模式:releaseShared

共享模式下在开释共享锁胜利后就间接调用doReleaseShared办法来解决了,上面再具体分析下

public final boolean releaseShared(int arg) {
        if (tryReleaseShared(arg)) {
            doReleaseShared();
            return true;
        }
        return false;
    }

共享模式:doReleaseShared

共享模式下的开释锁办法,须要唤醒后继并确保信号流传,然而在独占模式下,只须要唤醒head节点的后继即可。
1.head节点不为null且不等于tail节点的状况下

1.判断head节点的waitStatus如果等于SIGNAL,意味着要唤醒后继,多线程的状况下,只有一个线程能够胜利设置waitStatus为0,并且唤醒后继节点,其余线程会再次进入循环,然而不会进入SIGNAL分支了
2.判断head节点的waitStatus等于0且用CAS来更新waitStatus状态为PROPAGATE状态,只有一个线程能够胜利更新,其余线程会更新失败,会再次进入循环,但此时读取到的head节点的waitStatus肯定是PROPAGATE了,就不须要在循环了。
3.判断以后线程持有的head没有被其余线程批改,如果批改了就从新执行上述流程,否则就退出循环,到了这一步,其实head的waitStatus有俩种,一种为0,是在失常唤醒了后继节点的状况下,或者为PROPAGATE,在没有失常唤醒后继节点的状况。

    private void doReleaseShared() {
        for (;;) {
            Node h = head;
            if (h != null && h != tail) {
                int ws = h.waitStatus;
                if (ws == Node.SIGNAL) {
                    if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
                        continue;            // loop to recheck cases
                    unparkSuccessor(h);
                }
                else if (ws == 0 &&
                         !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
                    continue;                // loop on failed CAS
            }
            if (h == head)                   // loop if head changed
                break;
        }
    }

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理