Java 性能ConcurrentHashmap与HashMap

Java 性能ConcurrentHashmap与HashMap,java,collections,hashmap,Java,Collections,Hashmap,ConcurrentHashMap的性能与HashMap相比如何,尤其是.get()操作(我特别感兴趣的是只有很少的项,范围可能在0-5000之间) 有什么理由不使用ConcurrentHashMap而不是HashMap吗 (我知道不允许使用空值) 更新 只是想澄清一下,显然在实际并发访问的情况下性能会受到影响,但是在没有并发访问的情况下性能如何比较呢?我建议您对其进行测量,因为(出于一个原因)您存储的特定对象的散列分布可能有一定的依赖性。您希望得到什么答案 显然将取决于与写入同时发生的读取次数

ConcurrentHashMap的性能与HashMap相比如何,尤其是.get()操作(我特别感兴趣的是只有很少的项,范围可能在0-5000之间)

有什么理由不使用ConcurrentHashMap而不是HashMap吗

(我知道不允许使用空值)

更新


只是想澄清一下,显然在实际并发访问的情况下性能会受到影响,但是在没有并发访问的情况下性能如何比较呢?

我建议您对其进行测量,因为(出于一个原因)您存储的特定对象的散列分布可能有一定的依赖性。

您希望得到什么答案


显然将取决于与写入同时发生的读取次数,以及在应用程序的写入操作中正常映射必须“锁定”多长时间(以及您是否会使用
ConcurrentMap
上的
putIfAbsent
方法)。任何基准在很大程度上都是毫无意义的。

不清楚你的意思是什么。如果您需要线程安全性,您几乎没有选择—只有ConcurrentHashMap。而且在get()调用中肯定会有性能/内存方面的损失-如果你运气不好,可以访问易失性变量并锁定。

标准hashmap不提供并发保护,而并发hashmap提供。在它可用之前,您可以包装hashmap以获得线程安全访问,但这是粗粒度锁定,意味着所有并发访问都被序列化,这可能会真正影响性能

并发hashmap使用锁剥离,只锁定受特定锁影响的项。如果您在hotspot这样的现代虚拟机上运行,虚拟机将尝试使用锁偏置、协同和省略(如果可能的话),因此您只需在实际需要时为锁支付罚金


总之,如果您的映射将被并发线程访问,并且您需要保证其状态的一致性,请使用并发hashmap

线程安全是一个复杂的问题。如果您想使对象线程安全,请有意识地这样做,并记录该选择。使用您的类的人会感谢您,如果它在简化使用时是线程安全的,但是如果一个曾经是线程安全的对象在将来的版本中变得不安全,他们会诅咒您。线程安全,虽然真的很好,不只是圣诞节

现在来回答你的问题:

ConcurrentHashMap(至少在中)通过将基础映射划分为多个单独的存储桶来工作。获取元素本身不需要任何锁定,但它使用原子/易失性操作,这意味着内存障碍(可能非常昂贵,并干扰其他可能的优化)

即使JIT编译器可以在单线程的情况下消除所有原子操作的开销,仍然存在决定要查看哪个存储桶的开销——诚然,这是一个相对快速的计算,但是,不可能消除

至于决定使用哪个实现,选择可能很简单

如果这是一个静态字段,您几乎肯定会希望使用ConcurrentHashMap,除非测试表明这是一个真正的性能杀手。您的类与该类的实例具有不同的线程安全期望

如果这是一个局部变量,那么HashMap就足够了——除非您知道对该对象的引用可能泄漏到另一个线程。通过对映射界面进行编码,您可以在以后发现问题时轻松地对其进行更改

如果这是一个实例字段,并且该类没有被设计为线程安全的,那么将其记录为非线程安全的,并使用HashMap

如果您知道这个实例字段是该类不是线程安全的唯一原因,并且愿意接受承诺的线程安全性所暗示的限制,那么请使用ConcurrentHashMap,除非测试显示出显著的性能影响。在这种情况下,您可能会考虑允许类的用户以某种方式选择对象的线程安全版本,也许是通过使用不同的工厂方法。


在任何一种情况下,都应将类记录为线程安全(或有条件地线程安全),以便使用您的类的人知道他们可以跨多个线程使用对象,编辑您的类的人知道,他们将来必须维护线程安全。

对于1000个元素的哈希表,在整个表中使用10个锁可以节省近一半的时间,其中10000个线程正在插入,10000个线程正在删除

有趣的运行时差异是

始终使用并发数据结构。除非剥离的缺点(如下所述)成为频繁操作。在这种情况下,你必须获得所有的锁?我读到最好的方法是递归

当可以在不损害数据完整性的情况下将高争用锁断开为多个锁时,锁条带化非常有用。如果这是可能的或不应该采取一些思考,并不总是这样。数据结构也是决策的促成因素。因此,如果我们使用一个大数组来实现一个哈希表,那么对整个哈希表使用一个锁来同步它将导致线程顺序访问数据结构。如果这是哈希表上的同一个位置,那么这是必要的,但是,如果他们正在访问表的两个极端呢


锁条带化的缺点是很难获得受条带化影响的数据结构的状态。在本例中,表的大小,或者尝试列出/枚举整个表可能会很麻烦,因为我们需要获取所有的条带锁。

我真的很惊讶地发现这个主题如此古老,但还没有人提供任何tes