在JDK 8之前,还没有办法在Java中创建大型的线程安全的ConcurrentHashSet。 java.util.concurrent包甚至没有一个名为ConcurrentHashSet的类,但是从JDK 8开始,您可以使用新添加的keySet(默认值)和newKeySet()方法来创建由ConcurrentHashMap支持的ConcurrentHashSet。 与战术解决方案不同,例如将并发哈希映射与伪值一起使用或使用映射的设置视图,您无法在其中添加新元素。 JDK 8的keySet(defaultValue)和newKeySet()方法返回的Set是一个合适的集合,您还可以在其中添加新元素以及执行其他set操作,例如contains(),remove()等。这些方法仅在ConcurrentHashMap类中可用,而在ConcurrentMap接口中不可用,因此您需要使用ConcurrentHashMap变量来保存引用,或者需要使用类型转换来强制转换存储在ConcurrentMAp变量中的ConcurrentHashMap对象。

Java并发API具有流行的Collection类的并发版本,例如ArrayList的CopyOnArrayList,HashMap的ConcurrentHahsMap和HashSet的CopyOnWriteArraySet,但是Java中没有类似ConcurrentHashSet的东西。 即使CopyOnWriteArraySet是线程安全的,也不适合需要大型线程安全集的应用程序。 它仅用于集大小较小且只读操作远远超过写入操作的应用程序。

因此,当您向Java程序员询问如何在不编写自己的类的情况下创建ConcurrentHashSet时,许多人会说他们可以将ConcurrentHashMap与虚假值一起使用。 实际上,这也是Java所做的,因为如果您知道HashSet在内部使用具有相同值的HashMap。

但是,这种方法的问题是您有一个地图并且没有设置。 您不能使用虚拟值在ConcurrentHashMap上执行设置操作。 当某些方法需要一个集合时,您不能将其传递出去,因此它不是很有用。

另一个选择是,许多Java程序员都会提到您可以通过调用keySet()方法从ConcurrentHashMap中获取Set视图,该方法实际上返回一个Set,您可以在其中执行Set操作并将其传递给需要Set的方法。但是这种方法也有其局限性,例如Set由ConcurrentHashMAp支持,并且Map中的任何更改也将反映在Set中。 另一个限制是您不能在此键集中添加新元素,否则将引发UnsupportedOperationException。 看到
Java 8 in Action了解更多信息。

这两个限制现在已成为过去,因为JDK 8添加了newKeySet()方法,该方法从给定类型(其中值为Boolean.TRUE)返回由ConcurrentHashMap支持的Set。 与从keySet()方法返回的Set视图不同,您还可以将新对象添加到此Set中。 该方法也很重载,并且接受初始容量以防止Set的大小调整。

以下是在Java 8中创建ConcurrentHashSet的代码示例:

ConcurrentHashMap certificationCosts = new ConcurrentHashMap<>();
Set concurrentHashSet = certificationCosts.newKeySet();
concurrentHashSet.add("OCEJWCD"); //OK
concurrentHashSet.contains("OCEJWCD"); //OK
concurrentHashSet.remove("OCEJWCD"); //OK

顺便说一句,这并不是用Java创建并发的,大的,线程安全的Set的唯一方法。 您还可以使用新添加的,重载的keySet(默认值)方法来创建ConcurrentHashSet。 此方法使用给定的任何默认添加默认值(即Collection.add和Collection.addAll(Collection))返回ConcurrentHashMap中键的Set视图。

当然,这只能用于您可以对Set中的所有元素使用相同的值,这在大多数情况下是可以的,因为您实际上并不关心Set中的值。 请记住,HashSet还是一个对所有元素都具有相同值的HashMap,有关更多详细信息,请参见HashSet在Java内部的工作方式 。

这是在Java 8中使用keySet(mapped value)方法获取ConcurrentHashSet的示例:

ConcurrentHashMap certificationCosts = new ConcurrentHashMap<>();
Set concurrentHashSet = certificationCosts.keySet(246);
concurrentSet.add("Spring enterprise"); // value will be 246 but no error

您还可以与此Set一起执行其他Set操作,例如addAll(),remove(),removeAll(),retainAll(),contains()。 它也是线程安全的,因此可以在多线程Java应用程序中使用。 您可以了解有关真正不耐烦的Java SE 8上基于集合的操作的更多信息。

Java程序,用于从ConcurrentHashMAp创建ConcurrentHashSet。

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

import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;/*
* Java Program to remove key value pair from Map while
* iteration.
*/
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"); // will throw UnsupportedOperationExcetpion
System.out.println("after adding element into concurrent set: " + concurrentSet);// creating concurrent hash set in Java 8 using newKeySet() method
Set concurrentHashSet = certificationCosts.newKeySet();concurrentHashSet.add("OCEJWCD");
concurrentHashSet.contains("OCEJWCD");
concurrentHashSet.remove("OCEJWCD");
System.out.println("after adding element into concurrent HashSet: " + concurrentSet);// you can also use keySet(defaultValue) method to add element into Set
concurrentSet = certificationCosts.keySet(246);
concurrentSet.add("Spring enterprise"); // value will be 246 but no error}}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,如下所示:

线程“ main”中的异常java.lang.UnsupportedOperationException

在java.util.concurrent.ConcurrentHashMap $ KeySetView.add(ConcurrentHashMap.java:4594)在Demo.main(Demo.java:23)

这就是为什么我注释了该代码,但是,newKeySet()和keySet(mapped value)方法返回的Set允许您将新元素添加到Set中,那里没有错误。

顺便说一下,这不是用Java创建线程安全Set的唯一方法。 甚至在Java 8之前,都有一个名为CopyOnWriteArraySet的类,该类允许您在Java中创建线程安全集。 它类似于CopyOnWriteArrayList,并且仅适用于集合大小小的应用程序,并且您只读取唯一的操作,因为它每次写入时都会将Set中的所有元素复制到新的Set中。 有关真正不耐烦的信息 ,请参阅Java SE 8,以了解有关Java 8中并发集合的更多信息。

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

1.它最适合于集大小通常较小的应用,只读操作远远多于可变操作,并且您需要防止遍历期间线程之间的干扰。

2.这是线程安全的。

3.可变操作(添加,设置,删除等)非常昂贵,因为它们通常需要复制整个基础数组。

4.迭代器不支持可变删除操作。

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

6.迭代器在构造迭代器时依赖于数组的不变快照。

这就是如何在Java 8中创建ConcurrentHashSet的全部内容。 JDK 8 API不仅具有lambda表达式和流之类的主要功能,而且还具有这些小的更改,这些使您的日常编码更加容易。 使用newKeySet()方法在Java中创建ConcurrentHashSet并非易事。 您不需要使用带有伪造值的集合之类的地图,也不必使用keySet()返回的集合视图的局限性,后者不允许您向集合中添加新元素。

进一步阅读

  • 使用Lambda表达式从Java 8中的集合到流
  • Java 8中用于数据处理的流,收集器和可选项
  • Java 8实战

相关文章:

如何用Java 8编写Comparator?
如何在Java 8中读取文件?
如何在Java 8中加入String? 如何在Java 8中比较日期? 如何在Java 8中格式化日期? 如何在Java 8中对列表排序?

非常感谢您阅读本文。 如果您喜欢本教程,请与您的朋友和同事分享。

翻译自: https://www.javacodegeeks.com/2017/08/create-thread-safe-concurrenthashset-java-8.html

如何在Java 8中创建线程安全的ConcurrentHashSet?相关推荐

  1. java 线程中创建线程_如何在Java 8中创建线程安全的ConcurrentHashSet?

    java 线程中创建线程 在JDK 8之前,还没有办法在Java中创建大型的线程安全的ConcurrentHashSet. java.util.concurrent包甚至没有一个名为Concurren ...

  2. java 绘图 渐变_如何在Java 2D中创建渐变绘画?

    要更改图形形状的颜色,我们可以使用setPaint()方法.对于简单的着色,我们可以将颜色对象传递给此方法,例如Color.RED或Color.GREEN. 如果要使用渐变绘画进行绘画,则可以使用Gr ...

  3. JAVA中创建线程的三种方法及比较

    JAVA中创建线程的方式有三种,各有优缺点,具体如下: 目录 一.继承Thread类来创建线程 二.实现Runnable接口来创建线程 三.通过Callable和Future来创建线程 四.三种方式创 ...

  4. Java中创建线程的三种方式

    Java中创建线程主要有三种方式: 一.继承Thread类创建线程类 (1)继承Thread类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务.因此把run()方法称为执行体. ...

  5. JAVA中创建线程池的五种方法及比较

    之前写过JAVA中创建线程的三种方法及比较.这次来说说线程池. JAVA中创建线程池主要有两类方法,一类是通过Executors工厂类提供的方法,该类提供了4种不同的线程池可供使用.另一类是通过Thr ...

  6. react中纯函数_如何在纯React中创建电子邮件芯片

    react中纯函数 by Andreas Remdt 由Andreas Remdt 如何在纯React中创建电子邮件芯片 (How to create email chips in pure Reac ...

  7. 如何在Java 8中使用LocalDateTime格式化/解析日期-示例教程

    Java项目中的常见任务之一是将日期格式化或解析为String,反之亦然. 解析日期表示您有一个表示日期的字符串,例如" 2017-08-3",并且要将其转换为表示Java中日期的 ...

  8. Java开发中Netty线程模型原理解析!

    Java开发中Netty线程模型原理解析,Netty是Java领域有名的开源网络库具有高性能和高扩展性的特点,很多流行的框架都是基于它来构建.Netty 线程模型不是一成不变的,取决于用户的启动参数配 ...

  9. mye连接mysql数据库_MySQL_如何在Java程序中访问mysql数据库中的数据并进行简单的操作,在上篇文章给大家介绍了Myeclip - phpStudy...

    如何在Java程序中访问mysql数据库中的数据并进行简单的操作 在上篇文章给大家介绍了Myeclipse连接mysql数据库的方法,通过本文给大家介绍如何在Java程序中访问mysql数据库中的数据 ...

最新文章

  1. ServiceLoader的使用
  2. lwip可以用于发udp_CubeMX初始化正点原子STM32F407 LAN8720A调通LWIP
  3. 安娜·塞克泽沃斯卡的“小人物”
  4. python 字符串去重且相同字符最多出现2次_【Python】获取字符串中出现次数最多/少的字符...
  5. linux 内核/proc
  6. Html.RadioButtonFor和Html.DropDownListFor 用法--备忘
  7. Git学习(2)Git 安装
  8. SQL中使用WITH AS提高性能-使用公用表表达式(CTE)简化嵌套SQL(转载)
  9. python数据分析收获与心得体会_初次数据分析--我的心得体会
  10. 贵州省谷歌地球高程DEM等高线下载
  11. BeanUtils与PropertyUtils区别
  12. AXI 总线基本概念 - 如何理解outstanding传输
  13. 彻底理解python3的编码和解码过程
  14. 已满的c盘如何清理无用的文件
  15. python合并视频(mp4+mp3)
  16. 水文预报中的确定性系数如何计算确定
  17. 操作系统核心知识与重难点
  18. 网络对抗 Exp7 网络欺诈防范 20154311 王卓然
  19. 2017年深度学习必读31篇论文(附论文下载地址)
  20. Xcode一键发布到AppStore

热门文章

  1. SpringBoot @Resource注入的坑
  2. 通俗易懂,常用线程池执行的-流程图
  3. 如何设计一个高可用的运营系统
  4. mybatis入门(六)之SQL语句构建器类
  5. 面试经历—广州YY(欢聚时代)
  6. Oracle入门(十四F)之PL/SQL定义变量
  7. 使用Java 8 Stream像操作SQL一样处理数据(上)
  8. Shell入门(五)之参数
  9. 2012三年大专计算机试题医学,计算机原理2012年4月真题(02384)
  10. (转)如何保障微服务架构下的数据一致性?