java中有哪些併發的List?只知道一種的就太遜了

發表於2023-09-19

java中有很多list,但是原生支援併發的並不多,我們在多執行緒的環境中如果想同時操作同一個list的時候,就涉及到了一個併發的過程,這時候我們就需要選擇自帶有併發屬性的list,那麼java中的併發list到底有哪些呢?今天要給大家介紹的是ArrayListCopyOnWriteArrayListConcurrentLinkedDeque這幾個。

各種list的優缺點

當涉及到併發程式設計時,不同的 List 實現具有各自的優點和缺點。下面是對 ArrayListCopyOnWriteArrayListConcurrentLinkedDeque 的優缺點進行詳細比較的描述:

ArrayList:

  • 優點:

    • 簡單易用:ArrayList 是 Java 中最基本的動態陣列,易於理解和使用。
    • 高效的隨機訪問:由於內部基於陣列實現,因此具有良好的隨機訪問效能。
  • 缺點:

    • 非執行緒安全:ArrayList 不是執行緒安全的,當多個執行緒同時修改它時會出現競態條件。
    • 需要外部同步:為了使 ArrayList 在多執行緒環境下安全,需要額外的同步措施,如使用 Collections.synchronizedList

CopyOnWriteArrayList:

  • 優點:

    • 執行緒安全:CopyOnWriteArrayList 是執行緒安全的,多個執行緒可以同時讀取而不會出現問題。
    • 適用於讀多寫少的情況:由於寫操作會複製整個陣列,適用於讀多寫少的情況,例如日誌記錄。
  • 缺點:

    • 寫操作開銷大:每次寫操作都會複製整個列表,因此寫操作的開銷較大,不適合高頻寫入操作。
    • 資料不是實時的:由於寫操作的複製過程,讀操作可能會看到舊資料,因此不適用於需要實時資料的場景。

ConcurrentLinkedDeque:

  • 優點:

    • 高併發:ConcurrentLinkedDeque 針對高併發讀寫進行了最佳化,適用於需要高併發處理的情況。
    • 低延遲:新增和刪除操作的效能很好,不會導致鎖爭用。
  • 缺點:

    • 不支援隨機訪問:ConcurrentLinkedDeque 不支援隨機訪問元素,因為它是一個雙端佇列,只能從隊頭和隊尾進行操作。
    • 不適用於所有場景:不適合需要隨機訪問的場景,例如需要根據索引查詢元素的情況。

總的來說,選擇哪種 List 實現取決於您的具體需求。如果您需要高度併發且讀寫操作相對平衡,ConcurrentLinkedDeque 可能是更好的選擇。如果您主要進行讀操作且能夠容忍寫操作的開銷,CopyOnWriteArrayList 是一個不錯的選擇。如果您只在單執行緒環境下操作,ArrayList 可能是更簡單的選擇,但需要注意同步問題。

他們的實現原理

理解這些併發 List 實現的原理對於正確使用它們非常重要。以下是這些 List 的實現原理:

ArrayList:

  • 實現:ArrayList 基於動態陣列實現。它內部維護一個物件陣列,可以根據需要進行自動擴充套件。
  • 原理:ArrayList 支援隨機訪問,因為可以透過索引直接訪問元素。新增元素時,它會檢查容量是否足夠,如果不夠,會建立一個更大的陣列並將元素複製到新陣列中。這可能導致內部陣列的重新分配和複製,因此在多執行緒環境下需要額外的同步來確保執行緒安全。

CopyOnWriteArrayList:

  • 實現:CopyOnWriteArrayList 也是基於陣列實現的,但與普通的 ArrayList 不同,它在寫操作時不直接修改現有陣列,而是建立一個新的副本。
  • 原理:讀操作在不需要鎖的情況下併發執行,因為它們始終訪問當前的陣列。寫操作會複製當前陣列的內容到一個新陣列上,然後執行修改操作。這確保了讀操作不受寫操作的影響。雖然寫操作需要額外的記憶體和複製,但讀操作非常高效,適用於讀多寫少的場景。

ConcurrentLinkedDeque:

  • 實現:ConcurrentLinkedDeque 是一個雙端佇列,它使用節點來連線元素。每個節點都包含一個元素和指向前一個和後一個節點的引用。
  • 原理:在多執行緒環境下,ConcurrentLinkedDeque 使用CAS(比較並交換)操作來實現併發。新增元素時,它會在隊頭或隊尾建立新的節點,然後透過CAS操作將新節點連線到佇列中。刪除元素時,會透過CAS來更改節點的引用,以確保執行緒安全。由於沒有全域性鎖,ConcurrentLinkedDeque 允許高併發的新增和刪除操作,但不支援隨機訪問。

總之,這些併發 List 的實現原理都是為了在多執行緒環境下提供高併發效能和執行緒安全。不同的實現方式適用於不同的使用場景。

使用舉例

在多執行緒Java應用程式中,處理資料的併發訪問是一個常見的挑戰。這裡將介紹四種支援併發的容器:ArrayListCopyOnWriteArrayListConcurrentLinkedDeque的用法和程式碼實現。

ArrayList

使用示例

以下是一個使用ArrayList的示例:

List<String> arrayList = Collections.synchronizedList(new ArrayList<>());

// 新增元素
arrayList.add("元素1");
arrayList.add("元素2");

// 迭代元素
for (String element : arrayList) {
    System.out.println(element);
}

CopyOnWriteArrayList

使用示例

下面是一個使用CopyOnWriteArrayList的示例:

CopyOnWriteArrayList<String> copyOnWriteArrayList = new CopyOnWriteArrayList<>();

// 新增元素
copyOnWriteArrayList.add("元素1");
copyOnWriteArrayList.add("元素2");

// 迭代元素
for (String element : copyOnWriteArrayList) {
    System.out.println(element);
}

ConcurrentLinkedDeque

使用示例

ConcurrentLinkedDeque的使用示例如下:

ConcurrentLinkedDeque<String> concurrentLinkedDeque = new ConcurrentLinkedDeque<>();

// 新增元素
concurrentLinkedDeque.offer("元素1");
concurrentLinkedDeque.offer("元素2");

// 獲取並移除元素
String element = concurrentLinkedDeque.poll();
System.out.println("取出元素:" + element);

選擇最適合您的容器

在實際應用中,您應該根據需求選擇最適合的容器。如果需要高併發的讀取操作,可以考慮使用CopyOnWriteArrayList。如果需要高併發的新增和移除元素操作,可以使用ConcurrentLinkedDeque。最終,根據專案要求和效能需求來選擇適當的容器。

總結

Java提供了多種支援併發的容器,如ArrayList、CopyOnWriteArrayList、ConcurrentLinkedDeque。瞭解它們的用法和效能特點對於編寫高效的多執行緒程式至關重要。選擇正確的容器可以顯著提高應用程式的效能和可靠性。

更多內容請參考 www.flydean.com

最通俗的解讀,最深刻的乾貨,最簡潔的教程,眾多你不知道的小技巧等你來發現!

歡迎關注我的公眾號:「程式那些事」,懂技術,更懂你!

相關文章