HashMap挂起并发访问

时间:2016-08-04 07:37:29

标签: java multithreading concurrency hashmap java-7

我们有一个应用程序使用java.util.HashMap的实例 - 通过各种间接 - 共享,以便多个线程同时访问它。我们现在解决了这个问题,因为我们知道java.util.HashMap不是线程安全的,不应该同时访问。

在修复之前,以及我们发现的原因之后,我们升级了JDK(到IBM JDK 7 SR3),升级之后我们在该HashMap实例的get操作期间偶尔会挂起(挂起发生在getEntry()方法中。)

出于好奇,我想知道,HashMap内部会发生什么,导致挂起。影响并发访问行为的实现有何不同?

关于它出现的HashMap实现,IBM JDK与Oracle JDK和OpenJDK相同,后者又与Java8版本不同(使用Node数据结构)。

我相信,difference between java7u40 b43 vs b147表示升级时引入的更改。

我目前的假设是,挂起的原因与addEntry方法的更改有关,从 add-first-resize-after 更改为 resize-first -add-后

但是,是否有人确切了解并发访问期间究竟发生了什么?

2 个答案:

答案 0 :(得分:1)

当调用 hashmap.put(key,value)时,将检查HashMap阈值。如果地图大小超过此阈值,则将调整地图的大小,并重新调整所有条目。
在多线程环境中,这将使HashMap处于不一致状态。至少,您应该保护应用程序中使用同步或锁定写入HashMap的调用 我建议使用java.util.concurrent.ConcurrentHashMap。

答案 1 :(得分:0)

我最终调试了我们编写的单元测试,并在线程挂起/循环时检查HashMap的存储区。实际上,当两个线程同时调整地图大小时,它们会在存储桶中创建一个循环。它最终得到这样的结构:

bucket1[0].entry1.next = entry2;
bucket1[0].entry2.next = entry1;

可在此处找到更详细的说明Resizing the HashMap: dangers ahead