Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/399.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java HashMap在并发访问中挂起_Java_Multithreading_Concurrency_Hashmap_Java 7 - Fatal编程技术网

Java HashMap在并发访问中挂起

Java HashMap在并发访问中挂起,java,multithreading,concurrency,hashmap,java-7,Java,Multithreading,Concurrency,Hashmap,Java 7,我们有一个应用程序,它使用了java.util.HashMap的一个实例,该实例通过各种间接方式共享,以便多个线程同时访问它。我们现在已经解决了这个问题,因为我们知道java.util.HashMap不是线程安全的,不应该并发访问 在修复之前,以及我们发现的原因,我们对JDK进行了升级(升级到IBM JDK 7 SR3),升级之后,我们在该HashMap实例的get操作过程中偶尔遇到挂起(挂起发生在getEntry()方法中) 出于好奇,我想知道HashMap中发生了什么,导致了挂起。影响并发访

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

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

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

关于HashMap实现,ibmjdk似乎与oraclejdk和OpenJDK相同,后者又不同于Java8版本(使用
节点
数据结构)

我相信,这代表了升级带来的变化

我目前的假设是,挂起的原因与
addEntry
方法的更改有关,即从addfirstresizeafter更改为resizefirstaddafter


但是,有人确切地了解并发访问期间到底发生了什么吗?

我最终调试了我们编写的单元测试,并在线程挂起/循环时检查了HashMap的存储桶。事实上,当两个线程同时调整映射的大小时,它们会在bucket中创建一个循环。它最终的结构如下:

bucket1[0].entry1.next = entry2;
bucket1[0].entry2.next = entry1;
在这里可以找到更详细的解释

当调用hashmap.put(key,value)时,会检查hashmap阈值。如果映射大小超过此阈值,将调整映射的大小,并重新显示所有条目
在多线程环境中,这将使HashMap处于不一致的状态。至少,您应该通过使用同步或锁来保护应用程序中写入HashMap的调用。

我建议使用java.util.concurrent.ConcurrentHashMap

根据定义,数据竞争是不可预测和随机的。对JDK的更改可能是完全无关的某个地方的一个微小更改,导致某些进程需要更长的纳秒时间,从而加剧了问题。问题很可能一直存在,但从几百万分之一的机会变成了几千分之一的机会。如果不重新创建问题并进行线程转储,几乎肯定无法确定原因。线程安全不能通过测试来证明,只能通过仔细分析代码来证明。在
HashMap
中没有
getEntry()
addEntry()
方法。你确定你是在那里被绞死的吗?@OlivierGrégoire内部有。@Boristespider我错了。我们实际上可以编写一个单元测试,在HashMap上执行并发puts,它可以非常可靠地重现问题。在put或transfer期间,所有线程在遍历存储桶的链接列表时都会被卡住。我对旧的jdk7 impl、新的jdk7 impl和jdk8 impl都进行了测试,结果都卡住了。