2015-04-05 29 views
2

我为Minecraft服务器开发插件。最近在我的测试服务器上,从ArrayList或Hashmap中删除对象时,我一直有重复的崩溃。程序在从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) 

此外,由于有人在评论中问道,I've pastebinned the entire thread dump that Spigot puts out当它检测到的冻结。

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

回答

3

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

我有两个理论:

  • 东西没有正确同步正在进行更新到ArrayList。这可能导致另一个线程看到ArrayList的陈旧/不一致状态,导致不可预知的行为。这个可能就足以将remove操作置于一个无限循环中,尽管它不是很明显如何。

    也可能是一个不同步的HashMap更新。

  • 该应用程序根本就没有冻结。相反,它会花费很长时间,因为您拥有非常大的数据结构和/或非常昂贵的操作 ...。

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

+0

我花了几个小时试图让一切都同步 - 这是不可能的。我将不得不使用一个ConcurrentHashMap :(。 – Joehot200 2015-04-05 15:20:29

+0

+1)作为第二个理论。碰撞,不太可能发生,也可能是由不好的算法造成的。 – Unihedron 2015-04-06 11:01:57

+0

我最终在一个月后解决了这个问题,而是使用addAll()方法代替 – Joehot200 2015-05-28 12:55:21

0

如果你说这是随机发生的,但总是在List.remove行,这可能是一个并发问题,在你的程序中的另一个地方,另一个Thread正在迭代List。所以当你调用remove()时,你将会有一个ConcurrentModificationException

+1

但是,为什么并发问题会冻结服务器而不是引发错误?另外我认为并发将是不可能的,因为Spigot是一个单线程应用程序(我仍然可以检查)。 – Joehot200 2015-04-05 09:41:14

+1

@ Joehot200 Spigot是多线程的。 – 2015-04-05 14:46:53