2013-03-06 2 views
0

Я получаю сообщение об ошибке в цикле for (Entry ...), где после вызова dfs() он скажет, что это concurrentmodificationexception. Я не знаю, почему это происходит, хотя visitOrder не связан с циклом foreach. Как это можно зафиксировать?Java: исключение параллельной модификации

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++; 
    } 
} 
+0

Доступ к вашей карте осуществляется несколькими потоками, и один из них изменяет содержимое карты (используя метод 'dfs'), а другой поток перемещается по содержимому карты. Чтобы исправить это, вы можете использовать объект блокировки для синхронизации блока кода. –

+0

У меня есть две карты деревьев. Я думал, что это исправит? – user1375155

+1

Нет, если обе карты указывают на одну и ту же ссылку на объект карты. –

ответ

2

Здесь Javadoc для "класса ConcurrentModificationException":

Это исключение может быть выброшено с помощью методов, которые обнаруживаются одновременно модификации объекта, когда таких модификация недопустима.

Например, для одного потока обычно не допускается изменять a Collection, в то время как другой поток выполняет итерацию по нему. В общем случае результаты итерации в этих условиях не определены. Некоторые реализации Итератора (в том числе и для всех общих реализаций набора , предоставленных JRE) могут выбрать , если это обнаружение обнаружит это исключение. Итераторы, которые делают , известны как отказоустойчивые итераторы, так как они не срабатывают быстро и чисто, а скорее рискуют произвольным, недетерминированным поведением на неопределенное время в будущем.

Обратите внимание, что это исключение не всегда указывает, что объект имеет , который был одновременно изменен другим потоком. Если один поток выдает последовательность вызовов методов, которые нарушают договор объекта, объект может вызывать это исключение. Например, если поток изменяет коллекцию напрямую, в то время как она выполняет итерацию по коллекции с помощью отказоустойчивого итератора, итератор будет генерировать это исключение .

Как это происходит, это именно то, что вы делаете: изменение самой структуры, которую вы используете, в вашей петле «foreach».

РЕШЕНИЕ:

Если вы считаете, что ваш дизайн правильно, то заменить простой цикл: for (int i=0; i < myContainer.size(); i++) ...

+3

Стоит пояснить, что ваше обходное решение не является «исправлением» - исключение ConcurrentModificationException является законным индикатором того, что существует потенциальная проблема с кодом, написанным. Иногда хорошо использовать это решение и подавлять это исключение; однако делать это, не понимая, почему это произошло, - это рецепт неприятностей на дороге. – dimo414

1

Я не знаю, почему это происходит, даже если visitedOrder не связанные с циклом Еогеасп.

Вы пытаетесь изменить TreeMap во время чтения. Вы просто указываете ссылку здесь, в этой строке. Таким образом, это просто тот же TreeMap с другим именем ссылки.

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

Существует только одинTreeMap экземпляр, который создается, когда вы делаете new TreeMap<Integer, Integer>(). Переменная stack относится к этому экземпляру; переменная visitedOrder также относится к одному экземпляру.И когда вы вызываете dfs(int vertex, TreeMap<Integer, Integer> visited), параметр visited также относится к тому же TreeMap экземпляру.

Теперь вы повторяете набор записей этого экземпляра TreeMap в цикле for(Entry<Integer,.... Во время итерации вы вызываете метод dfs(int, TreeMap<Interge, Integer>) и в рамках этого метода вы вызываете put на TreeMap экземпляре и который модифицирует экземпляр; следовательно, ConcurrentModificationException.

Из кода, который вы указали, я понимаю, что вы пытаетесь преобразовать массив в TreeMap, выполнив DFS. Вы повторяете TreeMap по ссылке stack и пытаетесь заполнить visitedOrder. Чтобы устранить полученное исключение, просто укажите переменную visitedorder на экземпляр new TreeMap<Integer, Integer>().

Обратите внимание, что исправление, которое я предложил, предназначено для исправления исключения, сохраняя при этом поток кода и логику без изменений, поскольку у меня есть только ограниченное изображение вашего решения.

Смежные вопросы