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

46次阅读

共计 1486 个字符,预计需要花费 4 分钟才能阅读完成。

概述

跟之前的思路一样咱们也采纳自顶向下的办法来剖析 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;
        }
    }

正文完
 0