我下面的递归函数在“continue”语句上抛出一个 ConcurrentModificationException。我查看了一些关于 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 each 循环遍历所有子项,而是使用 for 循环。
最佳答案
如果您查看迭代器的 ArrayList
实现,它表明在 Iterator.next()
期间它会检查集合的大小是否已更改.
if (i >= elementData.length)
throw new ConcurrentModificationException();
即使使用带有 Collections.synchronizedList(n.children)
的同步版本也无济于事,因为它仍然使用相同的迭代器。
因此,如果您需要具有修改集合的并发访问权限,您有一些选择:
- 使用
Iterator.remove()
移除当前元素, - 使用允许并发修改的版本,例如
ConcurrentLinkedQueue
或ConcurrentLinkedDeque
或 - 使用另一个
List
来编写更改而不是迭代。
您可以尝试使用 LinkedList
- 我没有完整阅读源代码,但快速浏览一下它的 Iterator
似乎它在迭代时不受添加影响。
关于java.util.ConcurrentModificationException 但我没有删除,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27049547/