简体   繁体   English

Java:并发修改异常

[英]Java: concurrent modification exception

I am getting an error in the for(Entry...) loop where after calling dfs(), it will say concurrentmodificationexception. 我在for(Entry ...)循环中收到一个错误,在该循环中,在调用dfs()之后,它将说并发修改异常。 I don't know why it is happening even though visitedOrder is not related with the foreach loop. 我不知道为什么会发生这种情况,即使VisitedOrder与foreach循环无关。 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++;
    }
}

Here is the Javadoc for "Class ConcurrentModificationException": 这是“ Class ConcurrentModificationException”的Javadoc:

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. 例如,通常不允许一个线程修改Collection而另一个线程对其进行迭代。 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. 如果检测到此行为,则某些Iterator实现(包括JRE提供的所有通用集合实现的实现)可能会选择抛出此异常。 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. 碰巧的是,这正是您正在做的事情:修改您在“ foreach”循环中使用的结构。

WORKAROUND: 解决方法:

If you believe your design is correct, then substitute a simple for loop: for (int i=0; i < myContainer.size(); i++) ... 如果您认为设计是正确的,则将一个简单的for循环替换为: for (int i=0; i < myContainer.size(); i++) ...

I don't know why it is happening even though visitedOrder is not related with the foreach loop. 我不知道为什么会发生这种情况,即使VisitedOrder与foreach循环无关。

You are trying to modify the TreeMap while you are reading. 您正在尝试在阅读时修改TreeMap You are just pointing the reference here in this line. 您只是在此行中指向参考。 So its just the same TreeMap with different reference name. 因此,它只是具有不同引用名称的相同TreeMap。

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

There is just one TreeMap instance that is created when you do a new TreeMap<Integer, Integer>() . 当您执行new TreeMap<Integer, Integer>()时, 只会创建一个 TreeMap实例。 The stack variable refers to this instance; stack变量引用此实例; the visitedOrder variable also refers the same instance. visitedOrder变量也引用相同的实例。 And when you call dfs(int vertex, TreeMap<Integer, Integer> visited) , the visited parameter also refers to the same TreeMap instance. 并且当您调用dfs(int vertex, TreeMap<Integer, Integer> visited)visited参数也引用相同的TreeMap实例。

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 . 现在,您要在for(Entry<Integer,...循环中循环访问此TreeMap实例的条目集。在迭代时,您调用dfs(int, TreeMap<Interge, Integer>)方法,并且在此方法中,您可以调用TreeMap实例上的put并修改该实例;因此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. 根据您提供的代码,我的理解是,您正在尝试通过执行DFS将graph数组转换为TreeMap You are iterating over the TreeMap referenced by stack and trying to populate visitedOrder . 您正在遍历stack引用的TreeMap并尝试填充visitedOrder To resolve the exception you are getting, just point the visitedorder variable to a new TreeMap<Integer, Integer>() instance. 要解决您遇到的异常,只需将visitedorder变量指向一个new TreeMap<Integer, Integer>()实例。

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. 请注意,我建议的修复程序旨在修复异常,同时使您的代码流和逻辑保持不变,因为我对解决方案的了解有限。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM