单作者/单读者场景的HashMap或ConcurrentHashMap?

时间:2017-03-11 09:12:42

标签: java multithreading hashmap concurrenthashmap

以下是详细信息。

  1. 一个线程写入地图,另一个线程从中读取。
  2. 插入的密钥永远不会更新。
  3. 如果消费者线程未在地图中找到该值,则可以自行计算该值。它不会找到1%的值,因为它们不会被生产者线程计算出来。
  4. 当消费者要求一个值时,它应该尽快得到它。
  5. 在这种情况下,HashMap没有同步工作吗?或者我将不得不使用ConcurrentHashMap

5 个答案:

答案 0 :(得分:4)

如果您计划同时从多个线程读取和写入地图,则需要ConcurrentHashMapHashMap不会这样做,因为尝试与get同时执行put可能会导致错误行为。

如果写入线程在读取线程开始之前完成,则可以使用常规HashMap

答案 1 :(得分:2)

简短的回答是你需要ConcurrentHashMap

稍微长一点的解释是,有两个原因。首先,一个简单的HashMap冒险读者和作者线程同时处理HashMap的相同内部数据。要使HashMap保持其正确性,它显然必须以一种必须看起来作为对任何客户端的单个操作发生的方式更新多个内部属性。允许读者在作者忙于修改这些属性时查询HashMap可能会导致意外行为。

第二点是,在不使用Java的并发支持机制的情况下,一个线程所做的更改的可见性无法以可预测的方式提供给其他线程。因此,即使作者在读者查询HashMap之前完成,也无法保证读者会在作者离开时看到数据 - ConcurrentHashMap会解决此问题。

第一点是更有可能在单处理器机器上,其中编写器线程可以完成插入新值的部分工作,然后在读取器线程从部分更新的映射读取时产生。第二点更多的是多核机器上的一个问题,其中每个核心都有自己的共享内存版本,如果你使用并发机制,它只能与其他核心同步。

答案 2 :(得分:1)

我的回答是根据你的问题。

您应该使用ConcurrentHashMap,因为它是线程安全的,而HashMap不是线程安全的。

答案 3 :(得分:0)

假设读者和编写者是不同的线程,那么您确实需要一个线程安全的数据结构。这排除了使用裸(即非同步)HashMap

我可以想到三种选择。

  • 具有外部同步的HashMap。 (这需要谨慎实施。)

  • 使用HashMap换取Map(或其他Collections.synchronizedMap(...)班级)。如果读者和作者正在进行获取和放置,这将起作用。但是,如果需要迭代地图,就会出现问题。

  • 使用ConcurrentHashMap。唯一令人担忧的是,在低争用用例中,ConcurrentHashMap对高争用的支持可能有点代价。

当然,ConcurrentHashMap是最简单的选择。

答案 4 :(得分:0)

这是一个很好的问题。事实上,源代码确实看起来像你可以逃脱它。它看起来不像废弃节点中可能有任何循环导致您的线程卡住或任何东西。您最糟糕的情况似乎是您在调整大小或树形化操作期间没有看到实际存在的值。但是你无论如何都要在阅读线程中计算1%的值,所以这可能不会打扰你。

但我们需要在这里思考一下。内存重新排序可以为您提供对未初始化对象或部分初始化对象的引用。

我相信部分初始化的Node甚至可以给你误报。如果Node来自内存中之前也持有Node的位置,那么如果您从并发放置中看到其中一个,则应该可以看到错误的键值对其中一个来自垃圾收集之前。

这是极不可能的,内存重新排序应该只会给你更多的假阴性,但我会远离它,除非你有一个非常快速的方法来验证价值。