ConcurrentModificationException при обработке HashMap - PullRequest
1 голос
/ 21 февраля 2011

Я пытаюсь поместить HashMap <Object, List<Object>> в мою dataModel, но когда я вызываю метод template.process (), я получаю следующее исключение:

java.util.ConcurrentModificationException
    at java.util.HashMap$HashIterator.nextEntry(HashMap.java:793)
    at java.util.HashMap$KeyIterator.next(HashMap.java:828)
    at freemarker.template.SimpleCollection$SimpleTemplateModelIterator.next(SimpleCollection.java:142)
    at freemarker.core.IteratorBlock$Context.runLoop(IteratorBlock.java:157)
    at freemarker.core.Environment.visit(Environment.java:351)
    at freemarker.core.IteratorBlock.accept(IteratorBlock.java:95)
    at freemarker.core.Environment.visit(Environment.java:196)
    at freemarker.core.MixedContent.accept(MixedContent.java:92)
    at freemarker.core.Environment.visit(Environment.java:196)
    at freemarker.core.IteratorBlock$Context.runLoop(IteratorBlock.java:172)
    at freemarker.core.Environment.visit(Environment.java:351)
    at freemarker.core.IteratorBlock.accept(IteratorBlock.java:95)
    at freemarker.core.Environment.visit(Environment.java:196)
    at freemarker.core.MixedContent.accept(MixedContent.java:92)
    at freemarker.core.Environment.visit(Environment.java:196)
    at freemarker.core.Environment.process(Environment.java:176)
    at freemarker.template.Template.process(Template.java:232)

После просмотра некоторых статейи старые вопросы, я попытался использовать ConcurrentHashMap вместо того же результата.Я также попытался сделать копию, используя new HashMap<Object, List<Object>>(oldHashMap).Есть ли другие распространенные исправления этой проблемы, которые я мог бы попробовать?

РЕДАКТИРОВАТЬ: Я знаю общую причину исключений ConcurrentModificationException.Пожалуйста, отвечайте, только если вы можете помочь мне понять, почему фреймворк Freemarker генерирует эти исключения, ладно?=)

Спасибо!

Ответы [ 4 ]

3 голосов
/ 21 февраля 2011

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

Простой пример:

//throws an exception in the second iteration
for(String s: list){
   list.remove(s);//changes the collection
}

fix 1, поддерживается не всеми итераторами:

Iterator<String> iter = list.iterator();
while(iter.hasNext()){
    iter.next();
    iter.remove();//iterator still valid
} 

fix 2:

List<String> toRemove = ...;
for(String s: list){
   toRemove.add(s);
}
list.removeAll(toRemove);
0 голосов
/ 21 февраля 2011

Исключение означает, что во время итерации по карте что-то изменило содержимое карты.

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

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

0 голосов
/ 21 февраля 2011

Вы получите такую ​​проблему на List и Map, если будете делать что-то вроде этого:

List<A> list = ...; //a list with few elements
for(A anObject : list){
  list.add(anotherObject); //modify list inside the loop
}

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

Там есть некоторая информация об этом в Java API для TreeMap здесь .

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

Обратите внимание, что поведение итератора при быстром отказе не можетбыть гарантированным, так как, вообще говоря, невозможно сделать какие-либо жесткие гарантии при наличии несинхронизированной параллельной модификации.Отказоустойчивые итераторы создают исключительную ситуацию ConcurrentModificationException.Следовательно, было бы неправильно писать программу, которая зависела от этого исключения для ее корректности: поведение итераторов при быстром отказе следует использовать только для обнаружения ошибок.

0 голосов
/ 21 февраля 2011

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...