2014-07-23 5 views
-1

Это мой класс:Почему я получаю ConcurrentModificationException, хотя я использую блокировки?

public class AComplicatedclass { 
    private List<Connection> activeConnections; 
    private Lock lock = new ReentrantLock();   

    public void printConnections() { 
     lock.lock(); 
     for(Connection c : activeConnections){ //exception happens here 
      ...prints details about connection 
      activeConnections.remove(c); 
     } 
     lock.unlock(); 
    } 

    private class MyThread extends TimerTask { 

     public void run() { 
      lock.lock(); 
       ...can alter activeConnections.... 
      lock.unlock(); 
     } 

    } 
} 

Как вы можете видеть объект блокировки должен предотвратить проблемы из-за одновременный доступ к этому общему массиву. Тем не менее, когда вызывается метод printConnections(), я получаю ConcurrentModificationException в том, что for.

Почему? Совпадающих изменений нет!

+4

Пожалуйста, покажите, что вы делаете в петлю. «сделать что-то» очень неудобно – AlexR

+2

Вероятно, что «... сделать что-то ...» добавляет или удаляет элементы в activeConnections. –

+0

И вы можете захотеть взглянуть на ['Collections.synchronizedList()'] (http://docs.oracle.com/javase/7/docs/api/java/util/Collections.html # synchronizedList (java.util.List)), чтобы упростить код. –

ответ

4

Скорее всего, вы измените свою коллекцию внутри цикла. В документации по ConcurrentModificationException заявляет

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

Причина, по которой итератор выбрасывает исключение, заключается в том, что он больше не может определить, какой элемент должен быть возвращен дальше.

Так что, если вы хотите изменить свою коллекцию вам необходимо либо переключиться на что-то вроде CopyOnWriteArrayList или использовать Iterator явно, как в

Iterator<Connection> iterator = activeConenctions.iterator(); 
    while(iterator.hasNext()) { 
     Connection c = iterator.next(); 
     if(/* what ever */) { 
      iterator.remove(); 
     } 
    } 
+0

Выполнение этого дает мне IllegalStateException ... – Phate

+0

@Phate с директором Iterator access? Какой конкретный тип списка вы используете? Что еще вы делаете? – TheConstructor

+1

@Phate вам нужно вызвать 'iterator.next()', прежде чем вы сможете вызвать 'remove()'. Попробуйте это, как видно здесь, или в Рафаэле. Смешение 'Iterator' с' for' в той же 'Collection' не будет работать, поскольку Java всегда будет использовать новый' Iterator' для 'for'-loop. – TheConstructor

0

Согласно Javadoc из ConcurrentModificationException:

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

Это не имеет никакого отношения к несинхронизированному доступу.

Некоторые примеры проблемных операций:

  • текущий элемент итерации удаляется из коллекции, каким будет следующий элемент в этом случае?
  • Некоторые элементы, которые уже были повторены, удаляются и снова вставляются позже в коллекцию. Должен ли итератор показывать его снова, когда он достигает новой позиции?
1

Редактирование списка во время итерации почти всегда приводит к ConcurrentModificationException, даже если ваше приложение однопоточное.

Если вам нужно удалить элементы во время итерации, используйте итератор:

final Iterator<Connection> iterator = activeConnections.iterator(); 
while(iterator.hasNext()) { 
    final Connection connection = iterator.next(); 
    // ...prints details about connection 
    iterator.remove(); 
} 
+0

Это зависит от вашей коллекции; см. CopyOnWriteArrayList из моего ответа ;-) (но да, это самая распространенная вещь) – TheConstructor

+0

Спасибо за разъяснение. –

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