1. 程式人生 > >學習ConcurrentLinkedDeque原始碼

學習ConcurrentLinkedDeque原始碼

可以看到ConcurrentLinkedDeque實現的介面有Serializable, Iterable<E>, Collection<E>, Deque<E>, Queue<E>,相應的就有各個介面實現的特性,這個類比較突出的特性可能是Concurrent這個詞啦。

基於連結節點的無界ConcurrentLinkedDeque(併發雙端佇列)。併發插入,刪除和訪問操作可跨多個執行緒安全執行。當許多執行緒共享對公共集合的訪問權時,ConcurrentLinkedDeque是一個合適的選擇。與大多數其他併發集合實現一樣,此類不允許使用null元素。

其中Iterators 和 spliterators 是弱一致的。

主要有兩個屬性欄位,head表示佇列的隊首元素,tail表示隊尾。

在網上copy一個圖:

ConcurrentLinkedDeque的建構函式只有兩個

ConcurrentLinkedDeque當然可以用來當queue和stack實現來用,但是我們主要來看看deque的介面實現,前後兩種方法實現的方式一樣的,但是返回值會有區分。

隊首入隊 addFirst(e) offerFirst(e)
隊首出隊 removeFirst() pollFirst()
隊首讀取 getFirst() peekFirst()
隊尾入隊 addLast(e) offerLast(e)
隊尾出隊 removeLast() pollLast()
隊尾讀取 getLast() peekLast()

隊首入隊,用的都是private void linkFirst(E e) ,這裡會先建立一個newNode,然後使用CAS方式入隊,這裡感到奇怪的p = h,q這個寫法,那麼這是隻是定義一個名字,然後告訴他你是什麼型別?這好有迷惑性呀。隊尾入隊也是類似的,我想這個演算法極端情況的效率怎麼樣呢?

讓我們看看出隊的操作吧,然後執行unlink操作,刪除元素,裡面的操作還是有點複雜的。隊尾的操作也類似。

讀取操作比上面的操作應該簡單一些吧,其中有個succ操作來獲取隊首元素。

請注意,與大多數集合不同,size方法不是恆定時間操作。由於這些deques的非同步性質,確定元素的當前數量需要遍歷元素,因此如果在遍歷期間修改此集合,則可能報告不準確的結果。備註裡面還寫著在併發操作中,可能這個方法沒什麼用。不過這裡p ==(p=p.next)是什麼情況?

新增,刪除或檢查多個元素的批量操作,例如addAll(java.util.Collection <?extends E>),removeIf(java.util.function.Predicate <?super E>)或forEach(java.util。function.Consumer <?super E>),不保證以原子方式執行。例如,與addAll操作併發的forEach遍歷可能只會觀察到一些新增的元素。

參考:

https://www.jianshu.com/p/602b3240afaf

https://blog.csdn.net/chenleixing/article/details/44143641

https://docs.oracle.com/javase/9/docs/api/java/util/concurrent/ConcurrentLinkedDeque.html

https://segmentfault.com/a/1190000016284649