2014-11-20 46 views
3

我下面的遞歸函數在'continue'語句中拋出一個ConcurrentModificationException異常。我查看了ConcurrentModificationException中的一些帖子,並且所有問題似乎都是從元素中移除一個元素,但是我沒有刪除我的函數中的任何元素。java.util.ConcurrentModificationException但是我不刪除

我的函數如下所示:

public static void getRootedTreeHelper(Node n, boolean[] marked, String spacing){ 

     System.out.println(spacing + "in helper with " + n.getId()); 
     marked[n.getId()] = true; 
     if(n.children.isEmpty()) 
      return; 
     else{ 
      for(Node child : n.children){ 
       if(marked[child.getId()]) 
        continue; // ConcurrentModificationException is thrown here. 
       else{ 
        n.addChild(child); 
        spacing = spacing + "\t"; 
        getRootedTreeHelper(child, marked, spacing); 
       } 
      } 
     } 
    } 

按照要求:節點類的相關部分顯示如下

public class Node { 

    private int id; 
    ArrayList<Node> children; 

    public Node(int id) { 
     this.id = id; 
     children = new ArrayList<Node>(); 
    } 

    /** 
    * add node n to this node's children 
    * @param n 
    */ 
    public void addChild(Node n) { 
     children.add(n); 
    } 

    // getters and setters() 
    public int getId() { 
     return id; 
    } 
    public void setId(int id) { 
     this.id = id; 
    } 
} 

有沒有人有什麼想法?

編輯解決: 我沒有用每個循環遍歷所有的孩子,而是使用for循環。

+0

顯示您的節點類 – Venkatesh 2014-11-20 21:06:51

+0

n.children是什麼類型?你可以添加堆棧跟蹤? – flob 2014-11-20 21:08:41

+4

迭代時添加到列表時,也會發生同樣的'ConcurrentModificationException'。 – 2014-11-20 21:08:47

回答

2

ConcurrentModificationException的Javadoc:

請注意,此異常不會始終指出對象已經 被並處不同線程修改。 (...)對於
例如,如果一個線程直接修改了一個集合,但它是
使用快速迭代器迭代集合,迭代器 將引發此異常。

該錯誤是添加一個孩子到集合中,同時也迭代它。

當在for循環中增加時,迭代器檢測到錯誤,只檢測

+0

這種情況。問題是,因爲他創建了自己的初級'節點'類,他沒有這個設施。 – hfontanez 2014-11-20 21:19:34

+0

這可能是由迭代時任何[失敗]重入訪問引起的;線程不是必需的。 – user2864740 2014-11-20 21:35:25

4

如果您看一下ArrayList的Iterator實現,它會顯示在Iterator.next()期間它會檢查集合的大小是否已更改。

if (i >= elementData.length) 
    throw new ConcurrentModificationException(); 

即使使用同步版本Collections.synchronizedList(n.children)不會幫助,因爲它仍然使用相同的迭代器。

所以,如果你需要有一個修改集合的併發訪問,你有一些選擇:

  • 使用Iterator.remove()刪除當前元素,
  • 使用一個版本,它允許像ConcurrentLinkedQueueConcurrentLinkedDeque併發修改或
  • 使用另一個List寫入更改比迭代。

你可以嘗試LinkedList - 我還沒有完全讀取源,但在其Iterator快速瀏覽好像它是免疫而迭代增加。

相關問題