有没有理由使用同步的HashMap而不是ConcurrentHashMap?

时间:2017-12-01 09:10:37

标签: java concurrency thread-safety

在多线程应用程序中,是否有任何方案可以在需要时使用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<>();

并删除“同步”?

4 个答案:

答案 0 :(得分:3)

课程文档说明了这一点:

  

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

因此,如果您以原子方式关注这些情况,那么外部同步可能就是您所需要的。

似乎你确实关心这个问题,因为你做keySet(),这不是原子的,在你做for循环时可能会添加或删除其他条目

答案 1 :(得分:2)

不确定。如果您的使用模式仅在极少数情况下需要同步,则HashMap的开销将小于ConcurrentHashMap。这是你需要测量的东西。

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

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

答案 2 :(得分:2)

问题是对应用程序状态需求的重要性。如果你希望在put方法调用转换之后将map的字符串转换与state同步,那么你的代码只是解决方案。

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

key1:value1
key2:value2

然后你调用

put("key3","value3")

synchronized block确保您的字符串转换为

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

如果删除synchronized块并将map更改为某个同步实现,则只有同步部分才会自动执行。因此,方法调用的时间轴在某些情况下可能是: Thread1 put(x,x) Thread2 put(x,x) Thread1用于循环到字符串的转换 Thread2用于循环到字符串转换

因此,Thread1转换错误状态,因为Thread2足够快,可以在Thread1调用字符串转换之前放入一些新条目。

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

答案 3 :(得分:0)

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