Странное поведение ConcurrentModificationException

Я не понимаю, почему этот метод выдает исключение:

public void add(Object obj){
    gameObjects.add(obj); //here the exception happens
}

... в то время как это не:

public void add(Object obj){
    gameObjects.add(obj); // no exception actually happens here 
    gameObjects.remove(obj);
}

Почему это происходит, учитывая, что это исключение во время выполнения?

Исключение:

Exception in thread "Thread-0" java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
    at java.util.ArrayList$Itr.next(Unknown Source)
    at threads.Main.tick(Main.java:181)
    at threads.Main.run(Main.java:104)

Метод вызывается для метода тика внутри объекта.

gameObjects не равно нулю:

List<Object> gameObjects = new ArrayList<Object>(128);

person Kacper Lubisz    schedule 01.07.2013    source источник
comment
Это недостаточно информации. Во-первых, что является исключением. Кроме того, каков контекст этих звонков? Кто вызывает код и как?   -  person Daniel Kaplan    schedule 01.07.2013
comment
Каков тип игровых объектов?   -  person Cemafor    schedule 01.07.2013
comment
Что такое gameObjects? Это нуль?   -  person AllTooSir    schedule 01.07.2013
comment
ConcurrentModificationException возникает, когда вы изменяете список (путем добавления или удаления элементов) во время обхода списка.   -  person AllTooSir    schedule 01.07.2013
comment
Возможный дубликат: stackoverflow.com/q/8189466/738746   -  person Bhesh Gurung    schedule 01.07.2013
comment
Для всех отрицательных и близких голосов: на самом деле это не такой уж плохой вопрос, если он спрашивает, почему добавление вызова .remove() предотвращает создание исключения.   -  person asteri    schedule 01.07.2013
comment
Я думаю, что это задает то же самое, что и мой вопрос, немного по-другому. Поэтому я проголосовал за закрытие как дубликат. Но не голосуйте против, потому что я думаю, что это хороший вопрос, хотя то, как он был опубликован в начале, было плохим.   -  person Bhesh Gurung    schedule 01.07.2013


Ответы (4)


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

Если вы хотите добавить его, вам придется сделать это с помощью итератора.

person Captain Skyhawk    schedule 01.07.2013

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

Обратите внимание, что это не метод add, который проверяет наличие ConcurrentModificationException; скорее, коллекция проверяется на наличие изменений в конце каждой итерации цикла.

person arshajii    schedule 01.07.2013
comment
Но вызов метода Add никак не может знать о последующем вызове метода Remove, поэтому он не может рассуждать о чистом изменении и не создавать исключение. Я что-то упускаю? - person Theodoros Chatzigiannakis; 01.07.2013
comment
@TheodorosChatzigiannakis Метод add не проверяет одновременную модификацию. - person arshajii; 01.07.2013
comment
О да, ты прав, я только что видел трассировку стека. Глупо с моей стороны. - person Theodoros Chatzigiannakis; 01.07.2013

согласно документу.

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

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

person stinepike    schedule 01.07.2013

Вы не можете изменить один и тот же object во время обхода.

JavaDoc говорят

Итераторы, возвращаемые методами iterator и listIterator этого класса, являются отказоустойчивыми: если список структурно изменен в любой момент после создания итератора любым способом, кроме как с помощью собственных методов удаления или добавления итератора, итератор выдаст исключение ConcurrentModificationException.

Для получения более подробной информации перейдите по этим ссылкам. Они могут помочь вам учиться.

Исключение одновременной модификации http://docs.oracle.com/javase/6/docs/api/java/util/ConcurrentModificationException.html

person Ruchira Gayan Ranaweera    schedule 01.07.2013