如何在Java 8中创建线程安全的ConcurrentHashSet
阅读原文时间:2021年04月20日阅读:1

在JDK 8之前,无法在Java中创建大型,线程安全的ConcurrentHashSet。该java.util.concurrent包没有一个叫做ConcurrentHashSet的类,但是从JDK 8开始,可以使用新添加的keySet(默认值)和newKeySet()方法在Java中创建一个由ConcurrentHashMap支持的ConcurrentHashSet。这比旧的解决方案更好。keySet(defaultValue)和newKeySet()返回的SetJDK 8的方法是一个合适的集合,还可以添加新元素以及执行其他集合操作,例如contains(),remove()等。

这些方法只能在ConcurrentHashMap类中使用而不能在ConcurrentMap接口中使用,所以需要使用ConcurrentHashMap 引用变量来保存引用,或者可以使用类型转换来转换ConcurrentHashMap对象存储在ConcurrentMap变量中。

Java中的并发集合

Java Concurrency API具有流行Collection类的并发版本,例如用于ArrayList的CopyOnArrayList,用于HashMap的ConcurrentHahsMap和用于HashSet的CopyOnWriteArraySet,但没有Java中的ConcurrentHashSet。 即使CopyOnWriteArraySet的线程安全,它也不适合大型线程安全集的应用程序。它仅用于设置大小保持较小且只读操作数量远远超过写入操作的应用程序。 所以,当你向Java程序员询问如何创建ConcurrentHashSet时,没有编写自己的类,很多人会说他们可以使用具有相同值的ConcurrentHashMap。事实上,这也是Java创建HashSet的方法。

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

另一个选项是,许多Java程序员会提到,可以通过调用keySet()方法从ConcurrentHashMap获得一个Set视图,而keySet()方法实际上返回一个Set,也可以在其中执行Set操作,并将其传递给一个需要Set的方法,但这种方法也有其局限性。也将反映在Set中。另一个限制是无法在此键集中添加新元素,这样做会抛出UnsupportedOperationException。

无论如何,这两个限制都已经成为了过去式,因为JDK 8添加了newKeySet()方法,该方法返回由给定类型的ConcurrentHashMap支持的Set,其中值为Boolean.TRUE。

与keySet()方法返回的Set视图不同,还可以将新对象添加到此Set中。该方法也被重载并接受初始容量以防止Set的大小调整。

1.1使用newKeySet()的ConcurrentHashSet

创建ConcurrentHashSet的代码示例:

ConcurrentHashMap&ltString,Integer> certificationCosts = new ConcurrentHashMap<>(); 
Set<String> concurrentHashSet = certificationCosts.newKeySet(); 

concurrentHashSet.add("OCEJWCD"); //OK
concurrentHashSet.contains("OCEJWCD"); //OK 
concurrentHashSet.remove("OCEJWCD"); //OK
复制代码

这不是在Java中创建并发,大型,线程安全的Set 的唯一方法。

还可以使用新添加的keySet(默认值)方法来创建ConcurrentHashSet。此方法返回ConcurrentHashMap中键的Set视图,使用添加的给定公共默认值(即Collection.add()和Collection.addAll(Collection))。

1.2使用keySet的ConcurrentHashSet(默认值)

以下是使用keySet(映射值)方法获取ConcurrentHashSet的示例:

ConcurrentHashMap&ltString, Integer> certificationCosts = new ConcurrentHashMap<>();

Set<String>concurrentHashSet = certificationCosts.keySet(246); 
concurrentSet.add("Spring enterprise"); // 值为246
复制代码

你也可以用这个Set 执行其他Set操作,例如addAll(),remove(),removeAll(),retainAll(),contains()。

从ConcurrentHashMap创建ConcurrentHashSet

这是我使用java.util.concurrent.ConcurrentHashMap类中添加的新方法创建的大型,线程安全的并发集的完整的程序。

import java.util.Set; 
import java.util.concurrent.ConcurrentHashMap; 
/* 
* 从Map中删除键值对的程序
* 迭代 
*/ 


public class Demo { 
public static void main(String[] args) throws Exception { 

ConcurrentHashMap certificationCosts = new ConcurrentHashMap<>(); 

certificationCosts.put("OCAJP", 246); 
certificationCosts.put("OCPJP", 246); 
certificationCosts.put("Spring Core", 200); 
certificationCosts.put("Spring Web", 200); 
certificationCosts.put("OCMJEA", 300); 

Set concurrentSet = certificationCosts.keySet(); 
System.out.println("before adding element into concurrent set: " + concurrentSet); 

// concurrentSet.add("OCEJWCD");
// 将抛出UnsupportedOperationExcetpion System.out.println("after adding element into concurrent set: " + concurrentSet); 
// 使用newKeySet()方法 Set 在Java 8中创建并发哈希集

concurrentHashSet = certificationCosts 。newKeySet();
concurrentHashSet.add("OCEJWCD");
concurrentHashSet.contains("OCEJWCD"); 
concurrentHashSet.remove("OCEJWCD"); 

System.out.println("after adding element into concurrent HashSet:" + concurrentSet); 

// 可以使用keySet(defaultValue)方法将元素添加到Set 
concurrentSet = certificationCosts.keySet(246); 
concurrentSet.add("Spring enterprise"); 
// 值是246
} 
}

Output 
before adding an element into the concurrent set: 
[Spring Web, OCPJP, OCAJP, Spring Core, OCMJEA] 
after adding an element into the concurrent set: 
[Spring Web, OCPJP, OCAJP, Spring Core, OCMJEA] 
after adding an element into concurrent HashSet: 
[Spring Web, OCPJP, OCAJP, Spring Core, OCMJEA]
复制代码

可以看到,如果尝试向ConcurrentHashMap的keySet()方法返回的Set中添加新对象,它会抛出UnsupportedOperationExcepiton,如下所示: java.util.concurrent.ConcurrentHashMap $ 中线程“main”中的异常java.lang.UnsupportedOperationException Demo.main中的KeySetView.add(ConcurrentHashMap.java:4594) (Demo.java:23)

这就是我注释代码的原因,但是,由newKeySet()和keySet(mapping value)方法返回的Set允许向集合中添加新元素,这里没有错误。

顺便说一下,这不是在Java中创建线程安全集的唯一方法。

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

1。它最适合于很小的应用程序,只读操作数量远远超过可变操作,并且需要在遍历期间防止线程之间的干扰。

2.它的线程是安全的。

  1. rators不支持可变删除操作。

  2. 通过迭代器的遍历速度很快,不会遇到来自其他线程的干扰。

  3. rators在构建迭代器时能够保持数组的快照不变。

这就是如何在Java 8中创建ConcurrentHashSet。

转载于:https://juejin.im/post/5c8220f45188257dd9033d1f

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章