看ConcurrentLinkedQueue這個名字,應該叫併發鏈表隊列哈。html
ConcurrentLinkedQueue是一個基於連接節點的無界線程安全隊列,它採用先進先出的規則對節點進行排序,當咱們添加一個元素的時候,它會添加到隊列的尾部,當咱們獲取一個元素時,它會返回隊列頭部的元素。算法
ConcurrentLinkedQueue由head節點和tair節點組成,每一個節點(Node)由節點元素(item)和指向下一個節點的引用(next)組成,節點與節點之間就是經過這個next關聯起來,從而組成一張鏈表結構的隊列。默認狀況下head節點存儲的元素爲空,tair節點等於head節點。安全
當許多線程共享對公共集合的訪問權限時,ConcurrentLinkedQueue是一個合適的選擇。與大多數其餘併發集合實現同樣,此類不容許使用null元素。多線程
該實現採用有效的非阻塞算法,該算法基於Maged M.Michael和Michael L.Scott提出的 Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue Algorithms 中描述的算法。併發
迭代器是弱一致的,在迭代器建立時或以後的某個時刻返回反映隊列狀態的元素。它們不會拋出ConcurrentModificationException,而且可能與其餘操做同時進行。異步
經常使用的併發隊列有阻塞隊列和非阻塞隊列,前者使用鎖實現,後者則使用CAS非阻塞算法實現,使用非阻塞隊列通常性能比較好。性能
下面看看這個類的構造方法:this
方法的實現:線程
這裏要先說一下鏈表結構實現的兩個關鍵字段 head與tail,是用private transient volatile修飾:3d
能夠看到這兩個值是 Node,這個類的實現也比較關鍵。這裏有兩個屬性E item,和Node<E> next,對值得的操做用了sun.misc.Unsafe UNSAFE裏的方法實現。Node分別用來存在列表的首尾節點,其中head節點存放鏈表第一個item爲null的節點,tail則並非總指向最後一個節點。Node節點內部則維護一個變量item用來存放節點的值,next用來存放下一個節點,從而連接爲一個單向無界列表。
而後就是具體應用到相應的隊列的方法裏,好比offer方法的實現,將指定元素插入此隊列的尾部。第一是定位出尾節點,第二是使用CAS算法能將入隊節點設置成尾節點的next節點,如不成功則重試:
tail節點並不老是尾節點,因此每次入隊都必須先經過tail節點來找到尾節點,尾節點可能就是tail節點,也多是tail節點的next節點。代碼中循環體中的第一個if就是判斷tail是否有next節點,有則表示next節點多是尾節點。
而後還有poll方法的實現,檢索並刪除此隊列的頭部,若是此隊列爲空,則返回null。並非每次出隊時都更新head節點,當head節點裏有元素時,直接彈出head節點裏的元素,而不會更新head節點。只有當head節點裏沒有元素時,出隊操做纔會更新head節點:
首先獲取頭節點的元素,而後判斷頭節點元素是否爲空,若是爲空,表示另一個線程已經進行了一次出隊操做將該節點的元素取走,若是不爲空,則使用CAS的方式將頭節點的引用設置成null,若是CAS成功,則直接返回頭節點的元素,若是不成功,表示另一個線程已經進行了一次出隊操做更新了head節點,致使元素髮生了變化,須要從新獲取頭節點。
peek()方法的實現,檢索但不移除此隊列的頭部,若是此隊列爲空,則返回null。
這裏size()方法的實現,返回此隊列中的元素數。與大多數集合不一樣,size方法不是constant-time操做。因爲這些隊列的異步性質,肯定元素的當前數量須要遍歷元素,所以若是在遍歷期間修改此集合,則可能會報告不許確的結果。
還有remove方法的實現,若是隊列裏面存在該元素則刪除給元素,若是存在多個則刪除第一個,並返回true,否者返回false
發現一篇Importnew寫的不錯的博文:http://www.importnew.com/25668.html 對各類狀況還畫了圖
有什麼討論的內容,能夠加我公衆號: