5

我对 HashMap 有一个奇怪的问题。
有多个线程访问同一个 hashmap(不是线程安全的)。

有时,该过程会卡住。

当我检查线程堆栈时,我看到许多线程处于状态:

java.lang.Thread.State: RUNNABLE
    at java.util.HashMap.get(HashMap.java:303) 

请注意,这种情况非常罕见。并且不能按需复制。

为什么会卡住?

hashmap 上没有同步。

键是字符串

4

1 回答 1

22

有多个线程访问同一个 hashmap(不是线程安全的)。

听起来您在没有正确同步HashMap的线程环境中使用它。您遇到了内存损坏并且线程很可能因此而旋转的问题。您不能使用多个线程更新未同步的映射并从中读取。在某些情况下,您可以构建一个只读映射,然后在多个线程中不同步地共享它。HashMap

我建议改用使用ConcurrentHashMapHashMapCollections.synchronizedMap(...).

更详细地说,这里的问题有两个方面。在更改内部地图数据时,由于竞争条件,您不能有两个线程更新未同步的地图。锁定对于确保互斥锁和正确的数据同步是必要的。一个线程可能会做出其他线程看不到的更改,这可能会覆盖它们。

另一个问题是内存同步。如果一个线程更新HashMap其内存中的 ,其他线程不一定会获得地图存储的相同视图。在线程获得部分内存更新之前,这不是问题——其中一些HashMap内存已更新而其他部分尚未更新。例如,您可能会获取存储桶数组的一部分或存储桶存储的一部分,当遍历它们时会导致线程旋转。

多处理器盒运行线程代码更快的主要原因之一是线程可以使用每个处理器的缓存内存。缓存的内存是问题所在。一个处理器可能正在读取或更改其缓存内存,同时另一个处理器正在执行相同的操作。将本地缓存内存与中央存储同步是您需要担心的事情之一,也是同步如此重要的原因。

如果HashMap您使用的是仅由您的线程读取并且永远不会更新的预填充,那么它可能没问题。我高度依赖于每个线程如何获得对 new 的引用HashMap。如果HashMap构造了然后填充并通过它们的构造函数(或在它们启动之前)传递到线程中,那么你很好。但是,如果线程已经在运行,那么这取决于它们如何获得对地图的引用。根据具体情况和您的内存架构,他们可能仍会获得地图内存的部分副本。

于 2013-06-12T16:04:18.343 回答