程序在从HashMap中删除对象时挂起?

时间:2015-04-05 09:17:26

标签: java arraylist bukkit

我为Minecraft服务器开发插件。最近在我的测试服务器上,我一直在从ArrayList或Hashmap中删除对象时反复崩溃。

首先,它似乎只是从ArrayList中删除了一些内容。但是,现在看来它可以在从任何ArrayList / HashMap中删除某些内容时随机发生。

在此特定实例中,代码行为entlist.get(pl.getName()).remove(en);,周围代码为

for (LivingEntity en: remove) {
    i++;
    if (entlist.containsKey(pl.getName())) {
        entlist.get(pl.getName()).remove(en);
    }
    if (i > 2000) {
        try {
            throw new Exception("Too many entities to remove!!");
        } catch (Exception e) {
            e.printStackTrace();
        }
        break;
    }
}

entlist是HashMap<String, ArrayList<LivingEntity>> entlist = new HashMap<String, ArrayList<LivingEntity>>();

胎面转储专门将ArrayList#remove()列为问题。

[09:53:51 ERROR]: Current Thread: Server thread
[09:53:51 ERROR]:       PID: 14 | Suspended: false | Native: false | State: RUNN
ABLE
[09:53:51 ERROR]:       Stack:
[09:53:51 ERROR]:               java.util.ArrayList.remove(ArrayList.java:481)
[09:53:51 ERROR]:               a.e$4.run(Main.java:1786) //Line 1786 being the `entlist.get(pl.getName()).remove(en);` line from earlier.

Java版:

C:\WINDOWS\system32>java -version
java version "1.7.0_11"
Java(TM) SE Runtime Environment (build 1.7.0_11-b21)
Java HotSpot(TM) Client VM (build 23.6-b04, mixed mode, sharing)

此外,评论中有人在检测到冻结时{,3}}询问了。

为什么从ArrayList / HashMap中简单地删除一个冻结整个服务器的值?

2 个答案:

答案 0 :(得分:3)

还不完全清楚ArrayList的第481行是什么,但假设它是this one,很难看出ArrayList.remove(...)调用是如何“冻结”的。

我有两个理论:

  • 正在对ArrayList执行更新而未正确同步。这可能导致另一个线程看到ArrayList的陈旧/不一致状态,从而导致不可预测的行为。这个可能足以将remove操作置于无限循环中,尽管不是很明显如何。

    也可能是HashMap更新未同步。

  • 该应用程序根本没有冻结。相反,它花了很长时间 ...因为你有一个非常大的数据结构和/或非常昂贵的equals操作。

    您可以通过查看数据结构的大小和/或测量和记录该部分代码所用的时间来测试该理论(部分)。

答案 1 :(得分:0)

如果你说这是随机发生的,但总是在List.remove行上,这可能是一个并发问题,程序中的其他地方另一个Thread正在迭代List。因此,当您调用remove()时,您将遇到ConcurrentModificationException