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