Java 奇怪的HashMap异常(HashMap$节点不能强制转换为HashMap$TreeNode)
在另一个关于stackoverflow的问题被问到之后, () 我开始试验HashMap。以下是我编写的几行代码:Java 奇怪的HashMap异常(HashMap$节点不能强制转换为HashMap$TreeNode),java,hashmap,Java,Hashmap,在另一个关于stackoverflow的问题被问到之后, () 我开始试验HashMap。以下是我编写的几行代码: import java.util.HashMap; import java.util.Random; public class Concurrency { public static void putEntriesToMap(HashMap<String, String> hashMap) { for (int count = 0; count
import java.util.HashMap;
import java.util.Random;
public class Concurrency {
public static void putEntriesToMap(HashMap<String, String> hashMap) {
for (int count = 0; count < 10000; count++) {
hashMap.put(Integer.toString(count), Integer.toString(count));
Random random = new Random();
if (random.nextBoolean()) {
hashMap.remove(count + "");
}
}
}
public static void main(String[] args) throws InterruptedException {
final HashMap<String, String> hashMap = new HashMap<String, String>();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
putEntriesToMap(hashMap);
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
putEntriesToMap(hashMap);
}
});
t1.start();
t2.start();
t1.join();
t2.join();
}
}
然而,这对我来说似乎很奇怪,因为它看起来像是一个内部HashMap错误。
我知道并发性没有正确使用,但它是故意使用的
我试图用谷歌搜索这个例外,但几乎找不到任何信息
你能重现同样的异常吗
我正在使用oracle jdk 1.8.0\u 40
编辑:
首先,谢谢你的回答,我现在明白了。
我只想指出,我知道如何通过使用线程安全预防措施来避免程序崩溃,但我不知道为什么在给定情况下会抛出此异常。
托马斯在下面的评论中解释得很好。这在公认的答案中也得到了很好的解释。再次感谢:)。我在您的代码中也发现了相同的异常。我在
putenriestomap()
方法上添加了一个synchronized
修饰符,错误似乎停止了。问题是两个线程同时修改同一个映射。必须转换一个对象才能将条目放入。然而,第二个线程正在处理一个变异对象,它抛出一个ClassCastException
。因此,请确保没有两个线程同时访问同一个映射。synchronized
修饰符阻止所有其他线程对类/实例执行任何操作,如果其他线程正在执行相同的操作。同步的静态方法同步类本身,而同步的非静态方法只同步类的实例。我得到了相同的ClassCastException
,同时调用。我通过更改使用的实现进行了修复。这只是“并发未正确使用”的结果--HashMap
需要外部同步才能保证线程安全。这是可能的,当您不在不同线程之间同步时,这里的问题是什么?使用并发包中的集合:问题是,为什么这个例外如此奇怪。在查看HashMap代码之后,似乎节点对象是在TreeNode上铸造的,而不是TreeNode实例。这就是抛出异常的原因。但是,为什么只有当并发被错误地使用时才会发生这种情况呢?正如您所看到的,Java8的HashMap有一个名为treeify
的方法来改进内部存储。由于您没有以线程安全的方式使用映射(正如其他线程已经评论的那样),一个线程依赖于类TreeNode
的条目,而另一个线程很可能将相同的引用更改为类Node
的条目(两者都扩展map.entry
)。
Exception in thread "Thread-0" Exception in thread "Thread-1" java.lang.ClassCastException: java.util.HashMap$Node cannot be cast to java.util.HashMap$TreeNode
at java.util.HashMap$TreeNode.moveRootToFront(HashMap.java:1819)
at java.util.HashMap$TreeNode.treeify(HashMap.java:1936)
at java.util.HashMap.treeifyBin(HashMap.java:771)
at java.util.HashMap.putVal(HashMap.java:643)
at java.util.HashMap.put(HashMap.java:611)
at Concurrency.putEntriesToMap(Concurrency.java:9)
at Concurrency$1.run(Concurrency.java:27)
at java.lang.Thread.run(Thread.java:745)