Condition中的transferForSignal()方法的不解
通過enq放入同步隊列了,他自己會慢慢的爭搶鎖,就像synchronize中的wait,為什么這里要進行一次unpark?
先看下判斷條件。
ws>0,說明是1,是CANCELLED狀態,!compareAndSetWaitStatus(p, ws, Node.SIGNAL)) 什么時候把前一個節點(enq(node);返回當前節點的前一個節點,也就是原來的tail)賦值為SIGNAL狀態失敗?就是前一個節點是CANCELLED的時候,好吧這兩個好像是一個命題。
接著看為什么這里要進行一次unpakr?
10-12行的迷惑性就來源于此。實際上,就算去掉10-12行也是滿足正確性要求的。因為線程T2釋放鎖后,依然會將從隊頭開始的第一個非取消節點喚醒,該節點會繼續ConditionObject#await()中的工作(稍后回去分析)。10-12行是為了進一步提升性能,針對兩種情況:
- 如果插入node前,AQS內部等待隊列的隊尾節點就已經被取消,則滿足wc > 0
- 如果插入node后,AQS內部等待隊列的隊尾節點已經穩定,滿足tail.waitStatus == 0,但在執行ws >
0之后!compareAndSetWaitStatus(p, ws,
Node.SIGNAL)之前被取消,則CAS也會失敗,滿足compareAndSetWaitStatus(p, ws,
Node.SIGNAL) == false
這兩種情況下,提前喚醒node能夠在等待鎖的同時,預先完成一部分ConditionObject#await()中無需同步的工作。這部分成本不能被輕易忽視,因為條件隊列被應用最多的場景是高并發,大量線程累加起來的成本是很可觀的。
鏈接:https://www.jianshu.com/p/a932c184db52
在從condition隊列到同步隊列之前,tail節點被取消了
在從condition隊列到同步隊列之后,tail節點沒被取消,執行完ws > 0
之后,這段時間,被取消了?就通過!compareAndSetWaitStatus(p, ws, Node.SIGNAL)再判斷一下
這個時候偷偷的提前執行一波,就算不提前執行,AQS隊列會不斷的把取消節點取消掉,最終還是被unpark的。
總的意思就是為了提升性能,沒有這里也是合理的。
總結
以上是生活随笔為你收集整理的Condition中的transferForSignal()方法的不解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: springboot dubbo 问题记
- 下一篇: Netty事件传播机制