Возможно ли, что я получаю ConcurrentModificationException, когда все методы в моей программе синхронизированы? - PullRequest
0 голосов
/ 21 декабря 2011

Я получаю ConcurrentModificationException, хотя я синхронизировал все методы всей программы (включая статические методы и метод main).

У меня нет скрытых итераторов.

  1. Как это вообще возможно?!
  2. Что это значит?
  3. Как это исправить?

Ответы [ 7 ]

6 голосов
/ 21 декабря 2011
  1. A ConcurrentModificationException может быть вызвано тем же тем же потоком , который манипулирует коллекцией во время итерации по ней
  2. Это означает, что не следует изменять коллекции при их переборе, кроме как с помощью методов Iterator.remove() или ListIterator.add()
  3. см. 2.
3 голосов
/ 21 декабря 2011

Ну, для начала, если вы видите это, это возможно: если книга с птицами и птица не согласны, поверьте птице.

Теперь, как это может произойти?Трудно сказать точно, не видя ваш код, но трассировка стека исключений укажет на место, где это произошло;Что вы видите вокруг этого?

В общем, это произойдет, когда у вас, очевидно, одновременный доступ.Когда вы найдете место, в котором это происходит, спросите себя, какие темы могут туда попасть.

3 голосов
/ 21 декабря 2011

Если вы запустите это

List<Object> list = new ArrayList<Object>();
for(Object obj : list)
    list.remove(obj);

Вы получите комодификацию.Вы не можете изменить коллекцию, перебирая ее, не используя соответствующие функции.

Это можно решить с помощью следующего:

List<Object> list = new ArrayList<Object>();
for(Iterator<Object> itr = list.iterator(); itr.hasNext();)
    itr.remove();
3 голосов
/ 21 декабря 2011

ConcurrentModificationException НЕ относится к синхронизации.

Это связано с изменением коллекции при ее повторении. Как указывает Ли Райан, трассировка с полным стеком поможет нам указать, как вы ее получили.

Как правило, чтобы это исправить, вы не должны изменять саму коллекцию во время ее итерации.

3 голосов
/ 21 декабря 2011

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

, например

Collection<Object> objects = new ArrayList<Objects>(Arrays.asList("a","b"));
for (Object o : objects) {
    objects.remove(o); //throws exception
}

Вы должны добавить те, которые хотите удалить, в другую коллекцию и удалить их после завершения итерации по списку. В противном случае вы перебираете коллекцию объектов через ее iterator () и вызываете remove () на текущем итераторе.

1 голос
/ 21 декабря 2011

Javadoc для ConcurrentModificationException содержит ответ:

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

Способ исправить это - не делать этого.

Т.е. (как уже отмечали другие), если вам нужно одновременно выполнять итерацию и модификацию, используйте методы, предоставленные итератором, а не изменяйте коллекцию напрямую.

1 голос
/ 21 декабря 2011

Синхронизированный метод устанавливает блокировку на экземпляр объекта, с которым он работает.

Если объекты A и B обращаются к одной и той же коллекции, не имеет значения, синхронизированы ли A # doStuff и B # doStuff - они все равно могут выполняться одновременно.

Чтобы заблокировать коллекцию, вам, вероятно, нужна блокировка самой коллекции: синхронизированная (коллекция) в теле метода или мьютекс Java 5 (лучше).

(это и тот факт, что вы можете получить исключение ConcurrentModificationException даже в одном потоке, как указали другие).

...