AQS 里的 setHeadAndPropagate 以及关于 PROPAGATE 信号的疑问?
private void setHeadAndPropagate(Node node, int propagate) { Node h = head; // Record old head for check below setHead(node); /* * Try to signal next queued node if: * Propagation was indicated by caller, * or was recorded (as h.waitStatus either before * or after setHead) by a previous operation * (note: this uses sign-check of waitStatus because * PROPAGATE status may transition to SIGNAL.) * and * The next node is waiting in shared mode, * or we don't know, because it appears null * * The conservatism in both of these checks may cause * unnecessary wake-ups, but only when there are multiple * racing acquires/releases, so most need signals now or soon * anyway. */ if (propagate > 0 || h == null || h.waitStatus < 0 || (h = head) == null || h.waitStatus < 0) { Node s = node.next; if (s == null || s.isShared()) doReleaseShared(); } }
- 上面的 h == null (h = head) == null s == null 看起来好像只是为了防止空指针异常,还是真的会出现这些情况,这些情况都是啥场景啊?
- h == null 和(h = head) == null 为啥要检查两遍,看起来是 下一个时间节点,head 就可能变了,但如果考虑这种情况,检查两遍 难道就够吗?
private void doReleaseShared() { /* * Ensure that a release propagates, even if there are other * in-progress acquires/releases. This proceeds in the usual * way of trying to unparkSuccessor of head if it needs * signal. But if it does not, status is set to PROPAGATE to * ensure that upon release, propagation continues. * Additionally, we must loop in case a new node is added * while we are doing this. Also, unlike other uses of * unparkSuccessor, we need to know if CAS to reset status * fails, if so rechecking. */ 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; } }
上面引入的 PROPAGATE 状态,就是为了 setHeadAndPropagate 能够检测到而存在的吧。
- 上面这个函数看起来 一般情况下,只会执行一次循环(头节点没有变)
- 为啥要从 SIGNAL 到 0 再到 PROPAGATE 呢,是为了防 unparkSuccessor 一手吗?
- 感觉好多疑问,都不知如何说起…