📜  如何在Java中创建线程安全的 ConcurrentHashSet?

📅  最后修改于: 2022-05-13 01:54:35.745000             🧑  作者: Mango

如何在Java中创建线程安全的 ConcurrentHashSet?

在 JDK 8 之前创建线程安全 ConcurrentHashSet是不可能的,因为Java.util.concurrent 包没有一个叫做 ConcurrentHashSet 的类,但是从 JDK 8 开始,新添加的 keySet(默认)和 newKeySet() 方法来创建一个 ConcurrentHashSet在 ConcurrentHashMap 支持的Java中。

ConcurrentHashSet可以通过使用ConcurrentHashMap创建,因为它允许我们使用keySet(默认值)newKeySet()方法来返回 Set,它恰好是一个正确的 Set。这使我们可以访问必要的函数,如contains()、remove()等。这些方法只能在 ConcurrentHashMap 类中使用,而不能在 ConcurrentMap 接口中使用,因此我们需要使用 ConcurrentHashMap 引用变量来保存引用,或者我们可以使用类型转换来转换存储在 ConcurrentMap 变量中的 ConcurrentHashMap 对象。

这种方法的问题是只有一个map,没有set,不能使用虚值对ConcurrentHashMap进行set操作。当某些方法需要一个 Set 时,你不能传递它,所以它不是很有用。

另一种选择是通过调用keySet()方法,keySet()方法实际上返回一个Set,其中可以执行和传递Set操作,但是这个方法有它的局限性,我们不能向这个keyset添加新元素,因为它会抛出UnsupportedOperationException。

由于所有这些限制,引入了 newKeySet() 方法,该方法返回由给定类型的 ConcurrentHashMap 支持的 Set,其中值为布尔值。

如何使用 newKeyset() 创建 ConcurrentHashSet:

Java
// Create the ConcurrentHashMap
ConcurrentHashMap map
    = new ConcurrentHashMap<>();
 
// Create the set by newKeySet() method of ConcurrentHashMap
Set set = map.newKeySet();
 
// add() method
set.add("geeksforgeeks");
set.add("geeks");
 
// contains() method to check whether the element present or
// not it will return boolean value (true or false)
set.contains("geeks");
 
// remove() method to remove an element from set
set.remove("geeksforgeeks");


Java
// Create ConcurrentHashMap
ConcurrentHashMap map
    = new ConcurrentHashMap<>();
 
// Create Set using the map
Set set
    = map.keySet(246); // 246 is any default value
 
set.add("GeeksForGeeks"); // Value will remain same as 246
                          // but we will ge no error.
 
// We can use all the functions like contains(),remove(),etc.
// as discussed in the previous code snippet


Java
// Create ConcurrentHashMap
ConcurrentHashMap map
    = new ConcurrentHashMap<>();
 
// Create Set using the map
Set set
    = map.keySet(246); // 246 is any default value
 
set.add("GeeksForGeeks"); // Value will remain same as 246
                          // but we will ge no error.
 
// We can use all the functions like contains(),remove(),etc.
// as discussed in the previous code snippet


Java
// Java program to implement thread safe ConcurrentHashSet
 
import java.io.*;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
 
class GFG {
    public static void main (String[] args) {
       
        // Creating a map 
        ConcurrentHashMap map = new ConcurrentHashMap<>();
       
          map.put("Geeks",246);
          map.put("GeeksforGeeks",246);
          map.put("Java", 200);
          map.put("Java 8",200);
          map.put("Threads", 300);
           
          // Creating set using keySet()
          Set concSet = map.keySet();
       
          System.out.println("Initial set: " + concSet);
           
          // If we want to add element is the set like
          // concSet.add("Element"); this will throw an UnsupportedOperationExcetpion
         
          // Now as mentioned in the avobe format we have to
        // create the set using newKeySet()
          Set  penNameSet = ConcurrentHashMap.newKeySet();
         
        penNameSet.add("Flair");
        penNameSet.add("Reynolds");
        penNameSet.add("Cello");
       
          // Print the set
          System.out.println("before adding element into concurrent set: " + penNameSet);
       
          // Adding new Element in the set
          penNameSet.add("Classmate");
           
          // Print again to see the change
          System.out.println("after adding element into concurrent set: " + penNameSet);
           
          // Check element present or not
          if(penNameSet.contains("Reynolds"))
        {
          System.out.println("YES");
        }
          else
        {
          System.out.println("NO");
        }
           
          // We can check directly like this and it will return a boolean value
          System.out.println(penNameSet.contains("Reynolds"));
       
          // Remove any element from set
          penNameSet.remove("Cello");
          System.out.println("after removing element from concurrent set: "
                                    + penNameSet);
       
    }
}



上述示例并不是在Java中创建线程安全 Set 的唯一方法。

ConcurrentHashSet 使用keySet(默认值):

Java

// Create ConcurrentHashMap
ConcurrentHashMap map
    = new ConcurrentHashMap<>();
 
// Create Set using the map
Set set
    = map.keySet(246); // 246 is any default value
 
set.add("GeeksForGeeks"); // Value will remain same as 246
                          // but we will ge no error.
 
// We can use all the functions like contains(),remove(),etc.
// as discussed in the previous code snippet

Java

// Create ConcurrentHashMap
ConcurrentHashMap map
    = new ConcurrentHashMap<>();
 
// Create Set using the map
Set set
    = map.keySet(246); // 246 is any default value
 
set.add("GeeksForGeeks"); // Value will remain same as 246
                          // but we will ge no error.
 
// We can use all the functions like contains(),remove(),etc.
// as discussed in the previous code snippet


执行:

Java

// Java program to implement thread safe ConcurrentHashSet
 
import java.io.*;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
 
class GFG {
    public static void main (String[] args) {
       
        // Creating a map 
        ConcurrentHashMap map = new ConcurrentHashMap<>();
       
          map.put("Geeks",246);
          map.put("GeeksforGeeks",246);
          map.put("Java", 200);
          map.put("Java 8",200);
          map.put("Threads", 300);
           
          // Creating set using keySet()
          Set concSet = map.keySet();
       
          System.out.println("Initial set: " + concSet);
           
          // If we want to add element is the set like
          // concSet.add("Element"); this will throw an UnsupportedOperationExcetpion
         
          // Now as mentioned in the avobe format we have to
        // create the set using newKeySet()
          Set  penNameSet = ConcurrentHashMap.newKeySet();
         
        penNameSet.add("Flair");
        penNameSet.add("Reynolds");
        penNameSet.add("Cello");
       
          // Print the set
          System.out.println("before adding element into concurrent set: " + penNameSet);
       
          // Adding new Element in the set
          penNameSet.add("Classmate");
           
          // Print again to see the change
          System.out.println("after adding element into concurrent set: " + penNameSet);
           
          // Check element present or not
          if(penNameSet.contains("Reynolds"))
        {
          System.out.println("YES");
        }
          else
        {
          System.out.println("NO");
        }
           
          // We can check directly like this and it will return a boolean value
          System.out.println(penNameSet.contains("Reynolds"));
       
          // Remove any element from set
          penNameSet.remove("Cello");
          System.out.println("after removing element from concurrent set: "
                                    + penNameSet);
       
    }
}
输出
Initial set: [Threads, Java, GeeksforGeeks, Geeks, Java 8]
before adding element into concurrent set: [Cello, Reynolds, Flair]
after adding element into concurrent set: [Cello, Classmate, Reynolds, Flair]
YES
true
after removing element from concurrent set: [Classmate, Reynolds, Flair]

这些是在Java 8 中创建ConcurrentHashSet的方法。JDK 8 API 具有所有主要功能,如 lambda 表达式和流,以及这些使编写代码变得容易的小改动。

以下是 CopyOnWriteArraySet 的一些重要属性:

  • 最适合非常小的应用,只读操作的数量远远超过变量操作,需要防止线程之间在遍历过程中的干扰。
  • 它的线程是安全的。
  • 栅格不支持变量删除操作。
  • 通过迭代器的遍历速度很快,不会遇到其他线程的干扰。
  • 在构建迭代器时,测试器能够保持数组的快照不变。