Java 中併發集合的必要性


Java 中的併發集合

Java 是一種眾所周知的計算機語言,它支援併發和多執行緒。開發人員可以使用同步關鍵字來保證執行緒之間的正確同步。此外,Java 的集合框架還提供各種可用於儲存和操作資料的集合。

開發人員可以使用 synchronized 關鍵字使這些集合執行緒安全。在涉及多個執行緒併發執行的程式中,高效且安全地執行程式取決於此功能。

Java 中併發集合的必要性是什麼?

ArrayList、LinkedList、HashSet、HashMap 和 LinkedHashMap 只是 Java 集合框架中的一些類,它們並非旨在在多執行緒環境中安全使用。

這意味著如果我們在多個執行緒併發訪問這些集合的情況下使用它們,則結果需要更加準確。我們需要執行緒安全的類,多個執行緒可以訪問這些類而不會導致任何問題來解決此問題。

雖然我們可以使用 Collections.synchronizedList(list) 等方法同步這些集合,但這並不是最佳解決方案。

即使其他執行緒只需要讀取資料,當我們使用此方法時,一次只有一個執行緒可以訪問整個列表。這可能會導致機制效率降低。我們必須使用併發集合來更有效地管理併發訪問。這些集合是建立的,以便多個執行緒可以同時訪問它們而不會出現問題。

ConcurrentHashMap

ConcurrentHashMap 是 Java 5 中廣泛使用的集合類。它之所以受歡迎,是因為它為 Hashtable 或 Synchronized Map 類提供了併發選項,透過使用細粒度鎖定,可以實現更高的併發性。

使用 ConcurrentHashMap,許多讀取器可以同時訪問 Map,而 Map 的一部分會被鎖定以進行寫操作,具體取決於 Map 的併發級別。這有助於提供比同步對映更好的可擴充套件性。

演算法

  • 步驟 1 - 匯入 java.util.concurrent.* 包。這包含併發實用程式的類。

  • 步驟 2 - 定義一個名為 MyConcurrentHashMap 的類,其中包含 main 方法。這是程式的入口點。

  • 步驟 3 - 建立一個名為 concurrentHashMap 的 ConcurrentHashMap 類的例項。

  • 步驟 4 - 使用 put 方法向 concurrentHashMap 新增三個鍵值對。每個鍵值對錶示產品 ID 及其對應的產品名稱。

  • 步驟 5 - 使用 println 方法將 concurrentHashMap 的內容列印到控制檯。這將以無序的方式輸出 concurrentHashMap 的內容。

示例 1

此程式演示瞭如何在 Java 中使用 ConcurrentHashMap 類。

import java.util.concurrent.*;
public class MyConcurrentHashMap {
   public static void main(String[] args){
      ConcurrentHashMap<String, String> concurrentHashMap
      = new ConcurrentHashMap<>();
      concurrentHashMap.put("P001", "Apple Iphone");
      concurrentHashMap.put("P002", "Samsung Smartphone");
      concurrentHashMap.put("P003", "Google Pixel");
      System.out.println(concurrentHashMap);
   }
}

輸出

{P001=Apple Iphone, P003=Google Pixel, P002=Samsung Smartphone}

BlockingQueue

BlockingQueue 是 Java 5 中一個流行的集合類,它有助於實現生產者-消費者設計模式。它易於使用,並且為 put() 和 take() 函式內建了阻塞支援。

如果佇列已滿,put() 方法將等待;如果佇列為空,take() 方法將等待。因此,它可以更輕鬆地控制生產者和消費者之間材料的移動。

ArrayBlockingQueue 和 LinkedBlockingQueue 是 Java 5 中提供的 BlockingQueue 的兩個不同版本。它們都使用先進先出 (FIFO) 元素排列。ArrayBlockingQueue 是有界的,並由陣列支援,而 LinkedBlockingQueue 可能是無界的。

CopyOnWriteArrayList

CopyOnWriteArrayList 是一種資料結構,每次進行更新操作時都會建立底層 ArrayList 的克隆副本。JVM 會自動將此克隆副本與原始 ArrayList 同步。因此,執行讀取操作的執行緒不受影響。

但是,這種方法可能代價高昂,因為每次更新操作都會建立克隆副本。因此,如果頻繁的操作是讀取操作,則 CopyOnWriteArrayList 是最佳選擇。此資料結構是 ArrayList 的執行緒安全版本,允許插入重複項、空值和異構物件,同時保留其順序。

關於 CopyOnWriteArrayList 需要注意的一點是,它的迭代器無法執行刪除操作,並且在迭代器上呼叫 add() 和 set() 方法會導致 UnsupportedOperationException 執行時異常。此外,CopyOnWriteArrayList 的迭代器永遠不會丟擲 ConcurrentModificationException。

演算法

  • 步驟 1 - 程式將三個元件新增到名為“l”的物件中,該物件屬於 CopyOnWriteArrayList 類。即使主執行緒繼續迴圈遍歷列表,也會啟動一個新執行緒向其中追加一個新元素。

  • 步驟 2 - 為了保護迭代過程不受子執行緒可能對列表進行的任何更改的影響,軟體依賴於 CopyOnWriteArrayList 類。

  • 步驟 3 - 在列印列表中的每個元素(包括子執行緒新增的“Z”元素)後,會按順序列印整個列表。

示例 2

下面的程式演示瞭如何使用 CopyOnWriteArrayList 類來確保在迭代列表時執行緒安全。

import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
public class ConcurrentDemo extends Thread {
   static CopyOnWriteArrayList<String> l
   = new CopyOnWriteArrayList<String>();
   public void run(){
      // Child thread trying to
      // add new element in the
      // Collection object
      l.add("Z");
   }
   public static void main(String[] args)
   throws InterruptedException{
      l.add("W");
      l.add("X");
      l.add("Y");
      
      // We create a child thread
      // that is going to modify
      // ArrayList l.
      ConcurrentDemo t = new ConcurrentDemo();
      t.start();
      Thread.sleep(1000);
      
      // Now we iterate through
      // the ArrayList and get
      // exception.
      Iterator itr = l.iterator();
      while (itr.hasNext()) {
         String s = (String)itr.next();
         System.out.println(s);
         Thread.sleep(1000);
      }
      System.out.println(l);
   }
}

輸出

W
X
Y
Z
[W, X, Y, Z]

結論

在 Java 中使用多個執行緒與集合一起使用時,使用執行緒安全的集合(如 ConcurrentHashMap、BlockingQueue 和 CopyOnWriteArrayList)對於避免資料不一致性和提高程式效率至關重要。這些集合提供了各種功能以滿足不同的併發需求,並且可以提高涉及多執行緒的 Java 應用程式的效能。

更新於: 2023 年 5 月 15 日

2K+ 次檢視

開啟你的 職業生涯

透過完成課程獲得認證

開始學習
廣告
© . All rights reserved.