【问题标题】:Java:Can reading from a HashMap change its state?Java:从 HashMap 中读取可以改变它的状态吗?
【发布时间】:2012-11-02 16:58:30
【问题描述】:

对非同步HashMap 的并发更新显然会导致活锁或其他数据损坏;为避免这种情况,应使用并发版本或实施同步机制。

并发调用HashMap.get()可以改变HashMap的状态,比如重新散列吗?

更新:

除了吹毛求疵的数据结构行为的理论乐趣之外,一些评论者想知道这个问题的实际方面。

如果get() 没有改变HashMap 的状态(并且不能因为另一个原因导致活锁),那么单个线程可以提前创建一个HashMap,然后多个线程可以同时读取它.如果并发读取不安全,我们需要 ConcurrentHashMap 用于每个多线程访问,无论类型如何。

【问题讨论】:

标签: java hashmap hashtable state livelock


【解决方案1】:

来自java docs

如果多个线程同时访问一个哈希映射,并且至少有一个 的线程在结构上修改映射,它必须同步 外部。 (结构修改是添加或删除一个或多个映射的任何操作;仅更改与实例已包含的键关联的值不是结构修改。)

这意味着并发get()很好,不会引起状态变化。

此外,您可以随时查看source,了解有关它是如何构建的更多信息。

【讨论】:

  • +1 我找不到参考;-) 不同的映射实现可能会定义不同的结构修改(参见linkedhashmap),但在哈希映射的情况下,get 不是结构修改。
  • +1 从逻辑上讲,至少有一个写入线程需要同步这一事实并不意味着只有读取线程不需要同步。
【解决方案2】:

Javadocs 通常定义什么是地图的结构修改。 HashMap 声明get 不是会导致结构修改的操作。

但是,其他地图实现的行为有所不同。例如,a LinkedHashMap 可以使用访问顺序,此时get 是结构修改:

在按访问顺序链接的哈希映射中,仅使用 get 查询映射是一种结构修改。

【讨论】:

    【解决方案3】:

    如果你想知道HashMap.get()(这是Map接口的具体实现)内部发生了什么,你可以阅读实现的代码。

    但出于所有目的,您不应该关心函数是如何实现的以及它的作用!唯一重要的是函数自己实现它的契约(API + 类/函数 javadocs)。未来的实现可能会发生变化,因此依赖它是不好的做法。

    【讨论】:

    • 但这不是特定于实现的问题。了解是否可以从多个线程访问get()s 的HashMap 或是否应该同步是很重要的。我可以想到它的许多用途。
    • 如果你打算在并发环境中使用Map,为什么不使用并发集合:ConcurrentHashMap
    • 因为如果您只需要并发读取 - 避免使用 ConcurrentHashMap 的开销可能是一件好事。
    • 不要优化性能,优化正确性。然后,如果您有性能问题,请找到并修复它们。在多线程程序中查找和调​​试错误是困难,那么为什么要冒险呢?而且如果你使用Map接口,你将来也可以无缝更改实现
    【解决方案4】:

    如您所说,仅致电get() 肯定不会造成任何问题。但是,并发的非同步更新肯定会导致这种情况。在get() 方法中,它只会对成员调用hashcode() 方法,直到找到匹配项。在这种情况下不会进行更新。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-06
      相关资源
      最近更新 更多