2015-04-05 62 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