Java.util.ConcurrentModificationException But I am not removing
My below recursive function throws ConcurrentModificationException in continue statement. I have looked at several posts about ConcurrentModificationException and all the problems seem to be related to removing an element from an element, but I am not removing any element in my function.
My function is below:
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);
}
}
}
}
As requested: The relevant sections of the Node class are shown below
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 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;
}
}
Does anyone have any ideas?
Edit solution: Instead of using a for each loop to iterate over all children, I use a for loop.
source to share
From the ConcurrentModificationException
Javadoc:
Note that this exception does not always indicate that the object has been simultaneously modified by a different thread . (...) For
For example, if a thread modifies a collection directly while it is iterating over a build using a failover iterator, the iterator will throw this exception.
The error lies in adding a child to the collection and also iterating over it.
The error is only detected by the iterator when it is incremented in the loop for
.
source to share
If you look at the implementation of the Iterator ArrayList
, it shows that at runtime Iterator.next()
it checks if the size of the collection has changed.
if (i >= elementData.length)
throw new ConcurrentModificationException();
Even using the synchronized version from Collections.synchronizedList(n.children)
would not help as it still uses the same Iterator.
So, if you want concurrent access that modifies the collection, you have a choice:
- use
Iterator.remove()
to remove the current element, - use a version that allows parallel modification, for example,
ConcurrentLinkedQueue
orConcurrentLinkedDeque
or - use a different one
List
for recording changes than for iterating.
You can try LinkedList
- I haven't read the source in full, but a quick glance at it Iterator
seems like it is immune to additions during iteration.
source to share