java 奇怪的 HashMap 异常(HashMap$Node 不能转换为 HashMap$TreeNode)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/29967401/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 16:11:15  来源:igfitidea点击:

Strange HashMap exception (HashMap$Node cannot be cast to HashMap$TreeNode)

javahashmap

提问by pnadczuk

After another question asked on stackoverflow, (Java- Why this program not throwing concurrent Modification exception) I started to experiment with the HashMap. Here are a few lines of code which I wrote:

在 stackoverflow 上提出另一个问题(Java-为什么这个程序不抛出并发修改异常)之后,我开始尝试使用 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 < 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();
    }
}

Once upon a time (approx 1 in 20 runs), when executing this code, I get

曾几何时(大约 20 次运行中的 1 次),在执行此代码时,我得到

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.run(Concurrency.java:27)
    at java.lang.Thread.run(Thread.java:745)

This, however, seems strange to me, because it looks like it is an internal HashMap error. I know that the concurrency is not used correctly, but it is done on purpose.

然而,这对我来说似乎很奇怪,因为它看起来像是一个内部 HashMap 错误。我知道并发使用不正确,但它是故意完成的。

I tried to google the exception, but I found almost no info.

我试图用谷歌搜索异常,但我几乎找不到任何信息。

Can you even reproduce the same exception?

您甚至可以重现相同的异常吗?

I am using oracle jdk 1.8.0_40

我正在使用oracle jdk 1.8.0_40

EDIT:

编辑:

Firstly, thanks for answers, it is now clear for me. I just want to point out that I knew how to avoid the program from breaking by using thread safe precautions, but I didn't know why specifically this exception is thrown in given situation. Thomas has explained it very well in the comments below. It is also well explained in the accepted answer. Thanks again :).

首先,感谢您的回答,现在我很清楚了。我只想指出,我知道如何通过使用线程安全预防措施来避免程序中断,但我不知道为什么在特定情况下会抛出此异常。托马斯在下面的评论中很好地解释了它。在接受的答案中也很好地解释了这一点。再次感谢 :)。

采纳答案by HyperNeutrino

I also found the same exception with your code. I added a synchronizedmodifier on the putEntriesToMap()method, and the error seemed to stop occurring. The problem is that both threads are modifying the same map at once. There is an object that must be converted to put the entry in. However, the second thread is dealing with a mutated object, which throws a ClassCastException. So, make sure that no two threads are accessing the same map at once. The synchronizedmodifier stops all other threads from doing anything with the class/instance if another thread is doing the same. Synchronized static methods synchronize the class itself, whereas synchronized non-static methods only synchronize the instance of the class.

我也发现了与您的代码相同的异常。我synchronizedputEntriesToMap()方法上添加了一个修饰符,错误似乎停止了。问题是两个线程同时修改同一个映射。必须转换一个对象才能将条目放入。然而,第二个线程正在处理一个变异的对象,它抛出一个ClassCastException. 因此,请确保没有两个线程同时访问同一个映射。该synchronized修改将停止从与类/实例做任何事如果另一个线程做同样的其他所有线程。同步静态方法同步类本身,而同步非静态方法只同步类的实例。

回答by Clay

I was getting the same ClassCastExceptionwith concurrent calls to HashMap.computeIfAbsent. I fixed by changing the implmentation to use ConcurrentHashMap.

ClassCastExceptionHashMap.computeIfAbsent 的并发调用得到了相同的结果。我通过更改实现来使用ConcurrentHashMap 进行修复。