繁体   English   中英

是否有任何理由使用同步 HashMap 而不是 ConcurrentHashMap?

[英]Is there any reason to use a synchronized HashMap rather than ConcurrentHashMap?

在多线程应用程序中,是否存在在需要时使用带有同步的 HashMap 比使用 ConcurrentHashMap 更好的场景?

具体来说,我正在考虑一个应用程序,其中地图初始化如下:

Map<String,String> map = new HashMap<>();

每个线程访问映射只是为了更新它并立即将其转换为字符串,因此唯一的同步块是:

synchronized(map) {
    map.put(key,value);
    StringBuilder sb = new StringBuilder();
    for (String k: map.keySet())
        sb.append("("+k+","+map.get(k)+")");
}

在这种情况下,将初始化更改为:

Map<String,String> map = new ConcurrentHashMap<>();

并删除“同步”?

问题是从应用程序的角度来看什么对您很重要。 如果您希望在 put 方法调用后将映射的字符串转换与状态同步,则您的代码是唯一的解决方案。

如果我们说在您的同步之前地图的状态阻止了它:

  • 键 1:值 1
  • 键 2:值 2

然后你调用你的一段代码

key = "key3" and value="value3"

同步块确保字符串转换将

(key1,value1)(key2,value2)(key3,value3)

如果您删除同步块并将映射更改为某个同步实现,则唯一的同步部分将被放置。 因此,在某些情况下,方法调用的时间线可以是:

  • 线程 1 put(x,x)
  • 线程2放置(x,x)
  • Thread1 用于循环到字符串的转换
  • Thread2 用于循环到字符串的转换

所以 Thread1 转换了错误的状态,因为 Thread2 足够快,可以在 Thread1 调用字符串转换之前放置一个新条目。

通常,任何集合的同步实现仅在您希望将集合方法作为原子操作的情况下才有用。 如果您需要在相同的集合状态下协作更多方法,则必须每次从外部同步它们。

类文档是这样说的:

对于诸如 putAll 和 clear 之类的聚合操作,并发检索可能仅反映某些条目的插入或删除。 类似地,迭代器、拆分器和枚举返回反映哈希表在迭代器/枚举创建时或创建后的某个时刻的状态的元素。

因此,如果您以原子方式关心这些情况,则可能需要外部同步。

似乎您确实关心这一点,因为您执行keySet() ,这不是原子性的,在执行 for 循环时可能会添加或删除其他条目

当然。 如果您的使用模式仅在极少数情况下需要同步,那么HashMap开销将比ConcurrentHashMap少。 这是你需要衡量的东西。

当然,除非你正在做一些非常具体和性能密集的事情,否则你在性能方面使用哪一个可能并不重要。 但是,使用ConcurrentHashMap您不必担心自己执行synchronization ,因此不会出错。

一个更直接的问题是是否有任何理由使用Collections.synchronizedMap(new HashMap<>())而不是ConcurrentHashMap已经在许多地方讨论过,例如: ConcurrentHashMap vs Synchronized HashMap

有趣的是,concurrentHashMap 的性能非常接近非线程安全的 HashMap,并且比同步的 HasHmap 好得多。 所以我不认为同步的 HasHmap 在一般情况下会更好。 https://dzone.com/articles/java-7-hashmap-vs

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM