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