user1375155
user1375155

Reputation: 49

Java: concurrent modification exception

I am getting an error in the for(Entry...) loop where after calling dfs(), it will say concurrentmodificationexception. I don't know why it is happening even though visitedOrder is not related with the foreach loop. How can this be fixed?

public TreeMap<Integer, Integer> DFS()
{
    TreeMap<Integer, Integer> stack = new TreeMap<Integer, Integer>();
    TreeMap<Integer, Integer> visitedOrder = stack;
    for(int i = 1; i < graph[0].length-1; i++)
    {
        stack.put(i, 0);
    }
    for(Entry<Integer, Integer> vertex : stack.entrySet())
    {
        if(vertex.getValue() == 0)
            dfs(vertex.getKey(), visitedOrder);
    }
    System.out.println(visitedOrder.values());
    return visitedOrder;
}

public void dfs(int vertex, TreeMap<Integer, Integer> visited)
{
    visited.put(vertex, order++);
    int currVertex = vertex;
    for(int i = vertex; i < graph[0].length-1;i++)
    {
        if(graph[vertex][i+1] == 1)
        {
            dfs(++currVertex, visited);
            break;
        }
        currVertex++;
    }
}

Upvotes: 0

Views: 416

Answers (3)

Kshitij
Kshitij

Reputation: 361

There is just one TreeMap instance that is created when you do a new TreeMap<Integer, Integer>(). The stack variable refers to this instance; the visitedOrder variable also refers the same instance. And when you call dfs(int vertex, TreeMap<Integer, Integer> visited), the visited parameter also refers to the same TreeMap instance.

Now you're iterating over the entry set of this TreeMap instance in the for(Entry<Integer,... loop. While iterating, you call the dfs(int, TreeMap<Interge, Integer>) method and within this method, you invoke a put on the TreeMap instance and that modifies the instance; hence the ConcurrentModificationException.

From the code you've provided, my understanding is that you are trying to convert a graph array to a TreeMap by doing a DFS. You are iterating over the TreeMap referenced by stack and trying to populate visitedOrder. To resolve the exception you are getting, just point the visitedorder variable to a new TreeMap<Integer, Integer>() instance.

Note that the fix I've suggested is aimed at fixing the exception while keeping you code flow and logic unchanged as I only have a limited picture of your solution.

Upvotes: 0

Jayamohan
Jayamohan

Reputation: 12924

I don't know why it is happening even though visitedOrder is not related with the foreach loop.

You are trying to modify the TreeMap while you are reading. You are just pointing the reference here in this line. So its just the same TreeMap with different reference name.

    TreeMap<Integer, Integer> stack = new TreeMap<Integer, Integer>();
    TreeMap<Integer, Integer> visitedOrder = stack;

Upvotes: 1

paulsm4
paulsm4

Reputation: 121881

Here is the Javadoc for "Class ConcurrentModificationException":

This exception may be thrown by methods that have detected concurrent modification of an object when such modification is not permissible.

For example, it is not generally permissible for one thread to modify a Collection while another thread is iterating over it. In general, the results of the iteration are undefined under these circumstances. Some Iterator implementations (including those of all the general purpose collection implementations provided by the JRE) may choose to throw this exception if this behavior is detected. Iterators that do this are known as fail-fast iterators, as they fail quickly and cleanly, rather that risking arbitrary, non-deterministic behavior at an undetermined time in the future.

Note that this exception does not always indicate that an object has been concurrently modified by a different thread. If a single thread issues a sequence of method invocations that violates the contract of an object, the object may throw this exception. For example, if a thread modifies a collection directly while it is iterating over the collection with a fail-fast iterator, the iterator will throw this exception.

As it happens, that's precisely what you're doing: modifying the very structure you're using in your "foreach" loop.

WORKAROUND:

If you believe your design is correct, then substitute a simple for loop: for (int i=0; i < myContainer.size(); i++) ...

Upvotes: 2

Related Questions