Java 如何创建一个线程安全的ConcurrentHashSet
在JDK 8之前,创建线程安全的ConcurrentHashSet是不可能的,因为java.util.concurrent包中没有一个叫做ConcurrentHashSet的类,但是从JDK 8开始,新增加的keySet(默认)和newKeySet()方法可以在Java中创建一个ConcurrentHashSet,而ConcurrentHashMap也支持。
并发HashSet 等。这些方法只能在ConcurrentHashMap类中使用,不能在ConcurrentMap接口中使用,所以我们需要使用ConcurrentHashMap引用变量来保存引用,或者我们可以使用类型转换来转换存储在ConcurrentMap变量中的ConcurrentHashMap对象。
这个方法的问题是只有一个map,没有set,不能用虚拟值对ConcurrentHashMap进行set操作。当一些方法需要一个Set时,你无法传递它,所以它的作用不大。
另一个选择是通过调用keySet()方法,keySet()方法实际上返回一个Set,其中可以执行和传递Set操作,但这个方法有其局限性,我们不能向这个keyset添加新元素,因为它会抛出一个UnsupportedOperationException。
由于所有这些限制,引入了newKeySet()方法,该方法返回一个由给定类型的ConcurrentHashMap支持的集合,其值为布尔值。
如何使用newKeyset()创建ConcurrentHashSet。
// Create the ConcurrentHashMap
ConcurrentHashMap<String, Integer> map
= new ConcurrentHashMap<>();
// Create the set by newKeySet() method of ConcurrentHashMap
Set<String> 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中创建线程安全的Set的唯一方法。
使用的ConcurrentHashSet
// Create ConcurrentHashMap
ConcurrentHashMap<String, Integer> map
= new ConcurrentHashMap<>();
// Create Set using the map
Set<String> set
= map.keySet(246); // 246 is any default value
set.add("GeeksForGeeks"); // Value will remain same as 246
// but we will get no error.
// We can use all the functions like contains(),remove(),etc.
// as discussed in the previous code snippet
// Create ConcurrentHashMap
ConcurrentHashMap<String, Integer> map
= new ConcurrentHashMap<>();
// Create Set using the map
Set<String> 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 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<String,Integer> 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 above format we have to
// create the set using newKeySet()
Set <String> 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的一些重要属性。
- 它最适合于非常小的应用程序,只读操作的数量远远超过可变操作,而且有必要防止遍历过程中线程之间的干扰。
- 它的线是安全的。
- 栅格不支持变量删除操作。
- 通过迭代器的遍历是快速的,不会遇到其他线程的干扰。
- 在构建迭代器时,猛禽能够保持阵列的快照不变。