【问题标题】:Is there any reason to use a synchronized HashMap rather than ConcurrentHashMap?是否有任何理由使用同步的 HashMap 而不是 ConcurrentHashMap?
【发布时间】:2017-12-01 09:10:36
【问题描述】:

在多线程应用程序中,是否存在在需要时使用带同步功能的 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<>();

并删除“同步”?

【问题讨论】:

  • 为什么不用String sb = map.toString(); 替换它呢?具体格式?
  • @Kayaman 是的,仅用于格式。

标签: java concurrency thread-safety


【解决方案1】:

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

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

  • key1:value1
  • key2:value2

然后你调用你的代码

key = "key3" and value="value3"

同步块确保字符串转换将是

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

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

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

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

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

【讨论】:

    【解决方案2】:

    类文档是这样说的:

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

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

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

    【讨论】:

      【解决方案3】:

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

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

      一个更直截了当的问题是,是否有任何理由使用 Collections.synchronizedMap(new HashMap&lt;&gt;()) 而不是 ConcurrentHashMap,ConcurrentHashMap vs Synchronized HashMap 等许多地方都对此进行了讨论:ConcurrentHashMap vs Synchronized HashMap

      【讨论】:

        【解决方案4】:

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

        【讨论】:

          猜你喜欢
          • 2010-12-31
          • 2010-11-20
          • 2018-10-20
          • 1970-01-01
          • 2011-11-25
          • 2017-02-14
          • 2011-01-01
          • 1970-01-01
          相关资源
          最近更新 更多