能夠看到ConcurrentLinkedDeque實現的接口有Serializable, Iterable<E>, Collection<E>, Deque<E>, Queue<E>,相應的就有各個接口實現的特性,這個類比較突出的特性多是Concurrent這個詞啦。html
基於連接節點的無界ConcurrentLinkedDeque(併發雙端隊列)。併發插入,刪除和訪問操做可跨多個線程安全執行。當許多線程共享對公共集合的訪問權時,ConcurrentLinkedDeque是一個合適的選擇。與大多數其餘併發集合實現同樣,此類不容許使用null元素。java
其中Iterators 和 spliterators 是弱一致的。算法
主要有兩個屬性字段,head表示隊列的隊首元素,tail表示隊尾。segmentfault
在網上copy一個圖:api
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操做,刪除元素,裏面的操做仍是有點複雜的。隊尾的操做也相似。oracle
讀取操做比上面的操做應該簡單一些吧,其中有個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