1. 程式人生 > >[核心技術36問]20.併發包中的ConcurrentLinkedQueue和LinkedBlockingQueue有什麼區別?

[核心技術36問]20.併發包中的ConcurrentLinkedQueue和LinkedBlockingQueue有什麼區別?

20.併發包中的ConcurrentLinkedQueue和LinkedBlockingQueue有什麼區別?

    有時候我們把併發包下面的所有容器都習慣叫做併發容器,但是嚴格來講,類似ConcurrentLinkedQueue這種Concurrent*容器,才是真正代表併發。

  • Concurrent型別基於lock-free,在常見的多執行緒訪問場景,一般可以提供較高吞吐量;
  • 而LinkedBlockingQueue內部則是基於鎖,並提供了BlokingQueue的等待性方法。

    java.util.concurrent包提供的容器(Queue、List、Set),Map,從名字上可以大概區分為Concurrent,CopyOnWrite,Blocking*等三類,同樣是執行緒安全容器,可以簡單認為:

  • Concurrent型別沒有CopyOnWrite之類容器相對較重的修改開銷;
  • 但是,凡事都是有代價的,Concurrent提供了較低的遍歷一致性。即Concurrent是弱一致性的,當利用迭代器遍歷時,如果容器發生修改,迭代器仍然可以繼續遍歷;
  • 與弱一致性相對應的,就是同步容器常見的行為“fast-fail”,也就是檢測到容器在遍歷過程中發生了修改,則丟擲“ConcurrentModificationException”,不再繼續遍歷;
  • 弱一致性另外一個體現就是size等操作準確性是有限的,未必是100%正確;
  • 與此同時,讀取的效能具有一定的不確定性。

理解ConcurrentLinkedDeque和LinkedBlockingQueue的主要功能區別:

    常見的集合如LinkedList是個Deque,只不過不是執行緒安全的。有兩個特別的Deque實現,ConcurrentLikedDeque和LinkedBlockingQueue。Deque的重點是支援對佇列頭尾都進行插入和刪除,所以提供了特定的方法,如:

  • 尾部插入addLast(e),offerLast(e);
  • 尾部刪除removeLast(e),pollLast(e);

    從行為上看,絕大部分Queue都實現了BlockingQueue介面。在常規佇列操作上,Blocking意味著其提供了特定的等待性操作,獲取(take)時等待佇列進隊,或者插入(put)時等待隊列出現空位。

    另一個BlockingQueue經常被考察的點就是是否有界。

  • ArrayBlockingQueue是最典型的有界佇列,其內部以final的陣列儲存資料,陣列的大小就決定了佇列的邊界,所以在建立ArrayBlockingQueue時,都要指定容量;
  • LinkedBlockingQueue,容易被誤解為無界佇列,但其實其行為和內部程式碼都是基於有界的邏輯實現的,只不過如果我們沒有在建立佇列時就指定容量,那麼其容量限制就自動被設定為Integer.MAX_VALUE,成為了無界佇列;
  • SynchronousQueue,每個刪除操作要等待插入操作,每個插入操作也要等待刪除操作,內部容量為0;
  • PriorityBlockingQueue是無邊界的優先佇列,雖然嚴格意義上來講,其大小也要受到系統資源影響。
  • DelayedQueue和LinkedTransferQueue同樣是無邊界佇列,對於無邊界佇列來說,有一個自然的結果,就是put操作永遠不會發生像其他BlockingQueue那種等待情況。