如何在Java中建立執行緒安全的ConcurrentHashSet?


在本文中,我們將瞭解建立執行緒安全 HashSet 例項的各種可能性,並瞭解與 HashSet 等效的 ConcurrentHashMap。我們還將研究每種方法的優缺點。

在 JDK8 之前,我們無法建立執行緒安全的 ConcurrentHashMap,因為 JDK8 中的 java.util.concurrent 包不提供名為 ConcurrentHashSet 的類,添加了兩種新的方法,如下所述。ConcurrentHashMap 是允許我們在迭代時修改 Map 的 Map 實現。ConcurrentHashMap 操作是執行緒安全的。ConcurrentHashMap 不允許鍵和值為 null。

建立執行緒安全 ConcurrentHashSet 的方法

當談到ConcurrentHashSet時,可以透過利用ConcurrentHashMap來建立,它允許使用keySet(defaultValue)newKeySet()方法來獲取一個合適的 Set。這提供了對諸如 contains()、remove() 等函式的訪問。

  • keySet (預設值)

  • newKeySet()

使用 KeySet(defaultValue) 建立 ConcurrentHashSet

ConcurrentHashMap 類的keySet(defaultValue)方法提供了儲存在對映中的鍵的 Set 檢視。該集合由對映本身支援,這意味著對對映的修改將反映在集合中,反之亦然。

語法

public ConcurrentHashMap.KeySetView<K,V> keySet(default_value)

引數

在使用 ConcurrentHashMap 建立集合時傳遞 default_value

示例

//A Java program to demonstrate the implementation of a ConcurrentHashSet that ensures thread safety.

import java.io.*;
import java.util.*;

public class TutorialsPoint {
   public static void main (String[] args) {

      ConcurrentHashMap<String,Integer> map = new ConcurrentHashMap<>();

      map.put("Tutorials",1);
      map.put("Point",2);
      map.put("Java", 3);
      map.put("article on",4);
      map.put("Threads", 5);

      //Create a Set using concurrenthashmap
      Set intialSet = map.keySet(120); //The value 120 is an arbitrary default value
      System.out.println("Initial set: " + intialSet);

      // The value will remain unchanged as 120
      // but no error will be encountered.

      intialSet.add("Element");
      System.out.println("After removing an element " + intialSet);

      //Checking if the set contains if yes we will remove and print the set

      if(intialSet.contains("Threads")) {
         intialSet.remove("Threads");
         System.out.println("After removing an element " + intialSet);
      }
   }
}

輸出

Initial set: [Threads, Java, Tutorials, Point, article on]
After removing an element [Threads, Java, Tutorials, Element, Point, article on]
After removing an element [Java, Tutorials, Element, Point, article on]

缺點

在嘗試向集合新增新元素時,值將保持不變,即我們在建立集合時設定的預設值。

由於我們上面遇到的所有限制,這就是他們引入newKeySet()方法的原因,該方法返回一個由 ConcurrentHashMap 支援的 Set,其中與鍵關聯的值的型別為Boolean

如何使用 NewKeySet() 建立 ConcurrentHashSet

newKeySet()方法屬於 ConcurrentHashMap 類,它生成一個由 ConcurrentHashMap 支援的新集合,其中指定型別的元素對映到 Boolean.TRUE。

語法

public static <K> ConcurrentHashMap.KeySetView<K,Boolean> newKeySet()

下面提供的程式碼將使我們瞭解如何使用 newKeySet() 建立 ConcurrentHashSet。為了解決我們在第一種方法中遇到的所有問題,我們現在將使用newkeySet()

示例

// A Java program to demonstrate the implementation of a ConcurrentHashSet that ensures thread safety.

import java.io.*;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

public class TutorialsPoint {
   public static void main (String[] args) {

      // Creating a map
      ConcurrentHashMap<String,Integer> map = new ConcurrentHashMap<>();

      map.put("Tutorials",1);
      map.put("Point",2);
      map.put("Java", 3);
      map.put("article on",4);
      map.put("Threads", 5);

      Set <String> subjectsSet = ConcurrentHashMap.newKeySet();

      subjectsSet.add("Computer Networks");
      subjectsSet.add("DBMS");
      subjectsSet.add("OS");

      // displaying the values of set
      System.out.println("before adding an element into subjects set: " + subjectsSet);

      //use add() method to insert elements into the set
      subjectsSet.add("DSA");

      // Print the set again to verify the changes
      System.out.println("after adding an element into subjects set: " + subjectsSet);

      // we can use utilize contains() method to check presence of an element in a  set
      if(subjectsSet.contains("DSA"))
      System.out.println("Yes it is there");
      else
      System.out.println("No it is not there");

      // we can do it directly like this :subjectsSet.contains("DSA")); it returns boolean value

      // To remove an element from a set use remove() method
      subjectsSet.remove("OS");
      System.out.println("after removing an element from subjects set: " + subjectsSet);
   }
}

輸出

before adding an element into subjects set: [Computer Networks, OS, DBMS]
after adding an element into subjects set: [Computer Networks, DSA, OS, DBMS]
Yes it is there
after removing an element from subjects set: [Computer Networks, DSA, DBMS]

我們還有其他方法可以建立執行緒安全的 HashSet,但大多數情況下不使用,而且效率也低於我們上面討論的方法。

使用 Collections 工具類建立 ConcurrentHashSet

synchronizedSet()方法屬於 Java Collections 類,用於獲取一個由指定集合支援的同步(執行緒安全)集合。

在此方法中,我們利用java.util.Collections提供的synchronizedSet()方法來建立一個執行緒安全的 HashSet 例項。

語法

public static <T> Set<T> synchronizedSet(Set<T> s)

引數

此集合封裝在一個同步集合中。

示例

import java.io.*;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.Collections;
import java.util.HashSet;

public class TutorialsPoint {
   public static void main (String[] args) {

      Set<String> names= new HashSet<String>();
      //let’s Add values to the set using add()
      names.add("Hari");
      names.add("Revanth");
      names.add("Lokesh");
      names.add("Kiran");
      //Creating a synchronized set
      Set<String> synchronizedSet = Collections.synchronizedSet(names);
      System.out.println("Synchronized set is :"+synchronizedSet );
   }
}

輸出

Synchronized set is :[Revanth, Hari, Kiran, Lokesh]

它比上面討論的方法效率低。基本上,與實現低階併發機制的 ConcurrentHashMap 相比,synchronizedSet()將 Set 包裝到同步裝飾器中。

使用 CopyOnWriteArraySet 建立執行緒安全 Set

用於建立執行緒安全實現的最後一種方法是 CopyOnWriteArraySet。以下是建立 Set 例項的程式碼片段。

示例

Set<String> copyOnArraySet = new CopyOnWriteArraySet<>();
copyOnArraySet.add("sample");

以下是一些我們需要考慮的重要屬性和缺點:

  • 它使用陣列而不是 HashMap 來儲存資料,這意味著與採用 O(1) 的 ConcurrentHashMap 相比,contains() 或 remove() 等操作的複雜度為 O(n)。

  • 它適用於非常小的應用程式,我們需要防止執行緒在遍歷期間發生干擾。

  • 光柵不提供擦除變數的操作。

結論

在本文中,我們看到了建立執行緒安全 Set 例項的各種可能性。最初,我們探討了在 Java 中建立ConcurrentHashSet,它由 ConcurrentHashMap 支援。以及這些方法之間的區別,當需要執行緒安全的雜湊集時,這應該是首選方法

最後,我們還討論了 synchronizedSet()、CopyOnWriteArraySet 方法及其效能缺點。

更新於: 2023年10月16日

543 次瀏覽

開啟您的 職業生涯

透過完成課程獲得認證

開始
廣告