2014-11-20 39 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快速浏览好像它是免疫而迭代增加。

相关问题