ConcurrentHashMap有什么缺点吗?

5

我需要一个可以被多个线程访问的HashMap。

有两个简单的选择,使用普通的HashMap并在其上同步,或者使用ConcurrentHashMap。

由于ConcurrentHashMap在读操作时不会阻塞,因此它似乎更适合我的需求(几乎完全是读取,几乎从不更新)。 另一方面,我预计并发性非常低,因此不应该有阻塞(只需管理锁的成本)。

如果Map非常小(不到十个条目),是否有所不同?

与普通HashMap相比,读写操作的代价要高出多少(我假设它们是)?或者无论读/更新比率和大小如何,ConcurrentHashMap是否总是更好?


准确的重复问题?https://dev59.com/wHM_5IYBdhLWcg3wcCrc - andersoj
确实。谢谢。(尽管那里还没有令人满意的答案) - Thilo
4个回答

6
另一方面,我预计并发性非常低,因此不应该有阻塞(只是管理锁的成本)。
获取和释放一个Java互斥量(原始锁)的成本非常小。因此,如果您相信争用的概率非常低,则简单的HashMap可能是您最好的选择。
但这只是猜测。除非您已经对应用程序进行了分析,否则在推测性优化上花费的所有时间很可能都是浪费的时间。(* ...除非您有一个真正的好直觉。)

Stephen C 是正确的(他的声誉表明这是一种习惯)。在一般情况下,无争用锁定是快速的...也许我太快地使用 CHM 了。 - andersoj
扩展方面怎么样?预期和可能发生的完全不同。如果锁定/解锁很小,只需使用“ConcurrentHashMap”即可继续前进。 - TheLQ
1
@TheLQ - 除了锁定之外,使用ConcurrentHashMap的其他开销是我们关注的重点。你不能仅仅基于可扩展性可能成为问题的假设而将CCM应用于问题上。首先要进行测量! - Stephen C
你不能仅仅因为可扩展性可能成为问题就将CCM应用于问题上。这正是我想要的回答。现在,我只需要一些关于何时使用CHM的指导方针(因为并不是每个人都能够每次对其应用程序进行分析)。 - Thilo
4
除非你需要管理数千个ConcurrentHashMaps,否则其开销非常小,几乎不会被注意到。我的原则是:如果它将被多个线程访问和修改,请使用ConcurrentHashMap。这可以避免我浪费时间在仅在特定小条件下偶尔出现的线程问题上,这些问题并不总是在您的概要文件中显示。@Thilo,这个原则会起作用。 - TheLQ
1
@TheLQ - 啊。你的“有时才会出现的线程问题”评论意味着你试图通过CCMs解决的真正问题是地图没有正确同步。(而你所倡导的相当于用向量替换所有ArrayList,或用StringBuffer替换所有StringBuilder。) Thilo的问题是关于CCM与正确同步的HashMap之间的区别。 - Stephen C

2

相对于HashMap,CHM在使用原子操作时会承担一定的性能损失。具体损失有多少?猜猜看...在你的应用中进行测量吧... ;-)

如果你发现实际上存在性能问题,那么可能有一种非常专门的解决方案适用于小于10个条目,比任何由java.util组成的解决方案都要便宜,但在你确定存在性能问题之前不要轻易尝试。


我所关心的问题是在不知道是否存在性能问题之前,是否应该立即采用ConcurrentHashMap。如果在没有并发情况下CHM实际上比HashMap更慢,我是不想这么做的。 - Thilo
如果使用putIfAbsent()等函数可以立即得到所需的并发控制,我会选择使用CHM; 如果预先知道put()操作将会很复杂,我会使用synchronized(normalHashMap)。 (如果后续出现问题,优化任一方法都是可以的...) - andersoj

2

就吞吐量和性能而言,开销通常是可以忽略不计的。

另外,ConcurrentHashMap(实例级别)的内存占用略大于HashMap。如果您有大量小型CHM,则此开销可能会累加。


0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接