當一個線程執行任務失敗不影響其餘線程的進行 最大限度的利用CPU資源 能提升程序的伸縮性 伸縮性:不修改任何代碼 升級硬件就能帶來性能上的提升 升級硬件帶來的性能提升明顯 就是伸縮性良好java
代碼複雜 影響閱讀性 剛開始看ConcurrentLinkedQueue
的時候 沒有正確的思路,理解起來會比較費勁 我推薦直接用多線程同時執行的方式去理解 這樣會比較好node
offer()
入隊poll()
出隊public boolean offer(E e) { checkNotNull(e); //NullPointException檢查 final Node<E> newNode = new Node<E>(e); //包裝成一個Node對象 for (Node<E> t = tail, p = t;;) {//獲取當前尾節點 t=tail,p是真正的尾節點 p.next==null Node<E> q = p.next; if (q == null) { // p is last node if (p.casNext(null, newNode)) {//方法1 CAS更新 本身想3個線程同時進行這個操做 // Successful CAS is the linearization point // for e to become an element of this queue, // and for newNode to become "live". if (p != t) // hop two nodes at a time //方法2 延遲更新尾節點 下面說爲何 casTail(t, newNode); //方法3 成不成功無所謂 下面說 return true; } // Lost CAS race to another thread; re-read next } else if (p == q)// 方法4 學習offer方法時 能夠暫時放棄這一步 // We have fallen off list. If tail is unchanged, it // will also be off-list, in which case we need to // jump to head, from which all live nodes are always // reachable. Else the new tail is a better bet. p = (t != (t = tail)) ? t : head; else //去找到真正的尾節點 此處和方法2 應是相互輝映的存在 // Check for tail updates after two hops. p = (p != t && t != (t = tail)) ? t : q; //方法5 } }
自頂向下 思考CAS中可能出現的狀況 CAS是活鎖 所謂活鎖便是每一行代碼運行時 容許其餘線程訪問相同的代碼塊 成功與失敗並存 衍生了更多的條件判斷 本人以爲CAS方法都應該從這個方法去理解 再本身畫畫時序圖 (注意:理解offer()時,先把方法4排除
,由於4方法出現自引用的狀況 只有offer()
和poll()
交替執行時會出現 本文只介紹第一種狀況)算法
多線程操做多線程
offer()
offer()
和 poll()
方法交替執行同時執行offer()
(假設咱們如今有3個線程)併發
offer()
執行次數 最大爲n次 最少爲1次offer()
執行1方法CAS成功後 未更新尾節點(未執行3方法:兩種緣由 1是未知足前置條件if判斷 2是CAS更新失敗) 直接找next節點offer()
操做的點睛之筆 下面解釋只有offer()
操做時高併發
Thread 1執行完1方法成功 還未執行2方法 Thread2和Thread3進入5方法 ,也就是說Thread2和Thread3執行5方法發生在Thread1執行2方法以前 Thread2 and Thread3 invoke method5() before Thread1 invoke method2()
性能
此時 Thread2.p =q,Thread3.p=q, 由於p==t成立 時序圖以下,而後Thread1執行方法2 p==t 不執行tail尾節點的更新操做 由此可知 尾節點是延遲更新 一切爲了更高效~~~學習
圖1
Thread 2 與 Thread3 此時再次執行 1 方法 見圖1 他們此時的q.next==null 咱們規定Thread2 CAS成功 Thread3失敗了 成功後的時序圖以下 咱們假設 Thread3 invoke method5() after Thread2 invoke method2()
Thread2執行方法2 在 Thread3執行方法5以前this
圖2
對於Thread2 進入2方法 p!=t 知足 執行 casTail(t, newNode) 更新尾節點的快照 以下圖spa
圖3
Thread2 工做完成 退出循環
對於Thread3 由於執行1方法失敗 進入5方法 此時Thread3的tail快照t3
p = (p != t && t != (t = tail)) ? t : q;
按圖3來翻譯
p=(p!=t3&&t3!=(t3=t2))?t2:q;
p=t2;//直接去當前能獲取到的尾節點!!!
到這裏 offer()
方法解決完成
offer()
方法內 核心操做 就是 p=condition?result1:result2offer()
操做更新一次tail 單線程的環境下offer()
中的整個行爲想象爲跳臺階 result1的形式就像是 武俠小說中的越階戰鬥!!!result2的形式就是一步一個腳印 每次平穩地去下一個臺階offer()
最優的狀況 10個線程同時offer()
每個執行1方法成功的線程都沒有(執行2方法或則執行3方法失敗) 不要緊 尾節點的更新終會成功
每個失敗的線程都是去當前節點的next節點 p.next進行插入操做 在第9個線程(至關於咱們上文中的線程2)
當第10個線程操做時 雖然它很可憐 一直排到最後 可是尾節點更新一下就越過了9階!!!(不太恰當的地方請大佬們指點)
ConcurrrntLinkedQueue 優勢
offer()
插入的節點 直接去尾節點 直接跨過去ConcurrentLinkedQueue 缺點