1. 程式人生 > >【JUC源碼解析】ConcurrentLinkedQueue

【JUC源碼解析】ConcurrentLinkedQueue

阻塞 操作 turn == 技術 next .com 源碼解析 否則

簡介

ConcurrentLinkedQueue是一個基於鏈表結點的無界線程安全隊列。

概述

隊列順序,為FIFO(first-in-first-out);隊首元素,是當前排隊時間最長的;隊尾元素,當前排隊時間最短的。新元素,從隊尾插入;檢索元素,從隊首開始,Node的next屬性保證從隊首能遍歷到所有的有效元素。由於此隊列使用Node的next屬性聯接在一起,因此不允許有null元素。

隊列的實現具有非阻塞,弱一致性,滯後更新等特點。

隊列維護兩個指針,head指針和tail指針,一開始,head和tail都指向“啞巴”結點(Node的item屬性為空),新結點從尾部插入,隊列向後增長,然而,tail並不總是指向尾部(隊列中最後一個元素),head也並不總是指向頭部(隊列中第一個有效元素)。

head和tail的更新是獨立的,也就是說,tail指針很可能比head指針指向更靠前的結點(當然,此結點是已刪除結點,下次更新tail結點後,又跑到head結點後面或同一個),這保證了插入和刪除的獨立性。

hop,跳,指的是head或tail結點與第一個或最後一個結點的距離,大於等於2時更新。

新元素入隊時,最後一個結點的next域為null,隊列中的所有未刪除結點的item域不能為null且從head都可以在O(N)時間內遍歷到;對於要刪除的結點,不是將其引用直接置為null,而是將其item域先置為null(叠代器在遍歷時會跳過item為null的結點);允許head和tail滯後更新,即前文提到的head/tail指針並非總是指向隊列的頭/尾節點。

head結點(head指針指向的結點)的next域不能指向該結點自身,tail結點的next域可以指向該結點自己。

源碼解析

Node

1         volatile E item; // 元素內容
2         volatile Node<E> next; // 指向下一個結點

頭結點和尾結點

1     private transient volatile Node<E> head; // 頭結點
2     private transient volatile Node<E> tail; // 尾結點

入隊

 1
public boolean offer(E e) { 2 checkNotNull(e); // 為空,拋出異常 3 final Node<E> newNode = new Node<E>(e); 4 5 for (Node<E> t = tail, p = t;;) { // t作為tail的快照,p指向t結點 6 Node<E> q = p.next; // q是p的next結點 7 if (q == null) { // q為null,說明p是最後一個結點,可以直接插入 8 if (p.casNext(null, newNode)) { // 設置新結點為p的next結點 9 if (p != t) // 兩跳,更新tail結點 10 casTail(t, newNode); // 失敗,表示其他線程更新成功了 11 return true; // 返回 12 } 13 } else if (p == q) // p結點的next域指向了它自己,此操作在更新head結點時發生,表明此結點及其之前的結點已被刪除 14 p = (t != (t = tail)) ? t : head; // 如果tail結點已被其他線程更新,則p指向t(tail)結點,否則(tail指針指向已被刪除的結點),p指向head結點,跳到頭部,指向活著的結點 15 else 16 p = (p != t && t != (t = tail)) ? t : q; // p指向它的next結點(q),並在2跳時檢查tail結點是否更新,如果更新,則指向tail結點 17 } 18 }

初始隊列

技術分享圖片

【JUC源碼解析】ConcurrentLinkedQueue