Как отладить ConcurrentModificationException? [дубликат]

Я думаю, этот вопрос похож на ваш. Принятый ответ был:

$user = $this->getUser();
$user->addRole('ROLE_ADMIN');
$this->get('fos_user.user_manager')->updateUser($user);
$token = new UsernamePasswordToken($user, null, 'main', $user->getRoles());
$this->get('security.context')->setToken($token);

13
задан Juha Syrjälä 8 May 2009 в 15:29
поделиться

5 ответов

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

List<String> messages = ...;
for (String message : messages) {
    // Prone to ConcurrentModificationException
    messages.add("A COMPLETELY NEW MESSAGE");
}
31
ответ дан 1 December 2019 в 17:29
поделиться

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

1
ответ дан 1 December 2019 в 17:29
поделиться

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

for(String message : messages) {
  if (condition(message))
     messages.remove(message);
}

Другим распространенным примером является очистка карты.

Эта конкретная проблема может быть решена с помощью явного итератора.

for(Iterator<String> iter = messages.iterator(); iter.hasNext();) {
   String message = iter.next();
   if (condition(message))
       iter.remove(); // doesn't cause a ConcurrentModificationException 
}
12
ответ дан 1 December 2019 в 17:29
поделиться

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

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

import java.util.*;

/**
 * Created by IntelliJ IDEA.
 * User: francoiscassistat
 * Date: 12 juin 2010
 * Time: 18:20:18
 *
 *
 * Lockable list, made to debug ConcurrentModificationException on Lists.
 * The lock can be switched on/off with setLocked(boolean).
 * When locked, all write access to the list or iterators gets ConcurrentModificationException.
 * Simple usage case :
 *
 * list.setLocked(true);
 *
 * for (Object o : list.iterator()) // now this won't get ConcurrentModificationException, the other instruction that cause this will thrown the exception
 * { ... }
 *
 * list.setLocked(false);
 */
public class LockableList<E> implements List<E> {
    protected class LockableListIterator implements Iterator<E> {
        protected Iterator<E> iterator;

        public LockableListIterator(Iterator<E> iterator) {
            this.iterator = iterator;
        }

        public boolean hasNext() {
            return iterator.hasNext();
        }

        public E next() {
            return iterator.next();
        }

        public void remove() {
            checkLock();
            iterator.remove();
        }
    }

    protected class LockableListListIterator implements ListIterator<E> {
        protected ListIterator<E> listIterator;

        public LockableListListIterator(ListIterator<E> listIterator) {
            this.listIterator = listIterator;
        }

        public boolean hasNext() {
            return listIterator.hasNext();
        }

        public E next() {
            return listIterator.next();
        }

        public boolean hasPrevious() {
            return listIterator.hasPrevious();
        }

        public E previous() {
            return listIterator.previous();
        }

        public int nextIndex() {
            return listIterator.nextIndex();
        }

        public int previousIndex() {
            return listIterator.previousIndex();
        }

        public void remove() {
            checkLock();
            listIterator.remove();
        }

        public void set(E e) {
            checkLock();
            listIterator.set(e);
        }

        public void add(E e) {
            checkLock();
            listIterator.add(e);
        }
    }

    protected class LockableListSubList implements List<E>
    {
        protected List<E> list;

        public LockableListSubList(List<E> list) {
            this.list = list;
        }

        public int size() {
            return list.size();
        }

        public boolean isEmpty() {
            return list.isEmpty();
        }

        public boolean contains(Object o) {
            return list.contains(o);
        }

        public Iterator<E> iterator() {
            return new LockableListIterator(list.iterator());
        }

        public Object[] toArray() {
            return list.toArray();
        }

        public <T> T[] toArray(T[] a) {
            return list.toArray(a);
        }

        public boolean add(E e) {
            checkLock();
            return list.add(e);
        }

        public boolean remove(Object o) {
            checkLock();
            return list.remove(o);
        }

        public boolean containsAll(Collection<?> c) {
            return list.containsAll(c);
        }

        public boolean addAll(Collection<? extends E> c) {
            checkLock();
            return list.addAll(c);
        }

        public boolean addAll(int index, Collection<? extends E> c) {
            checkLock();
            return list.addAll(index, c);
        }

        public boolean removeAll(Collection<?> c) {
            checkLock();
            return list.removeAll(c);
        }

        public boolean retainAll(Collection<?> c) {
            checkLock();
            return list.retainAll(c);
        }

        public void clear() {
            checkLock();
            list.clear();
        }

        @Override
        public boolean equals(Object o) {
            return list.equals(o);
        }

        @Override
        public int hashCode() {
            return list.hashCode();
        }

        public E get(int index) {
            return list.get(index);
        }

        public E set(int index, E element) {
            checkLock();
            return list.set(index, element);
        }

        public void add(int index, E element) {
            checkLock();
            list.add(index, element);
        }

        public E remove(int index) {
            checkLock();
            return list.remove(index);
        }

        public int indexOf(Object o) {
            return list.indexOf(o);
        }

        public int lastIndexOf(Object o) {
            return list.lastIndexOf(o);
        }

        public ListIterator<E> listIterator() {
            return new LockableListListIterator(list.listIterator());
        }

        public ListIterator<E> listIterator(int index) {
            return new LockableListListIterator(list.listIterator(index));
        }

        public List<E> subList(int fromIndex, int toIndex) {
            return new LockableListSubList(list.subList(fromIndex, toIndex));
        }
    }

    protected List<E> list;
    protected boolean locked;

    public LockableList(List<E> list) {
        this.list = list;
        locked = false;
    }

    public boolean isLocked() {
        return locked;
    }

    public void setLocked(boolean locked) {
        this.locked = locked;
    }

    protected void checkLock() {
        if (locked)
            throw new ConcurrentModificationException("Locked");
    }

    public int size() {
        return list.size();
    }

    public boolean isEmpty() {
        return list.isEmpty();
    }

    public boolean contains(Object o) {
        return list.contains(o);
    }

    public Iterator<E> iterator() {
        return new LockableListIterator(list.iterator());
    }

    public Object[] toArray() {
        return list.toArray();
    }

    public <T> T[] toArray(T[] a) {
        return list.toArray(a);
    }

    public boolean add(E e) {
        checkLock();
        return list.add(e);
    }

    public boolean remove(Object o) {
        checkLock();
        return list.remove(o);
    }

    public boolean containsAll(Collection<?> c) {
        return list.containsAll(c);
    }

    public boolean addAll(Collection<? extends E> c) {
        checkLock();
        return list.addAll(c);
    }

    public boolean addAll(int index, Collection<? extends E> c) {
        checkLock();
        return list.addAll(index, c);
    }

    public boolean removeAll(Collection<?> c) {
        checkLock();
        return list.removeAll(c);
    }

    public boolean retainAll(Collection<?> c) {
        checkLock();
        return list.retainAll(c);
    }

    public void clear() {
        checkLock();
        list.clear();
    }

    @Override
    public boolean equals(Object o) {
        return list.equals(o);
    }

    @Override
    public int hashCode() {
        return list.hashCode();
    }

    public E get(int index) {
        return list.get(index);
    }

    public E set(int index, E element) {
        checkLock();
        return list.set(index, element);
    }

    public void add(int index, E element) {
        checkLock();
        list.add(index, element);
    }

    public E remove(int index) {
        checkLock();
        return list.remove(index);
    }

    public int indexOf(Object o) {
        return list.indexOf(o);
    }

    public int lastIndexOf(Object o) {
        return list.lastIndexOf(o);
    }

    public ListIterator<E> listIterator() {
        return new LockableListListIterator(list.listIterator());
    }

    public ListIterator<E> listIterator(int index) {
        return new LockableListListIterator(list.listIterator(index));
    }

    public List<E> subList(int fromIndex, int toIndex) {
        return new LockableListSubList(list.subList(fromIndex, toIndex));
    }
}

Просто используйте его вот так :

List list = new LockableList(new ArrayList(...));
list.setLocked(true);

for (E e : list.iterator())
{ ... }

list.setLocked(false);

Надеюсь, это может помочь кому-то еще.

5
ответ дан 1 December 2019 в 17:29
поделиться

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

4
ответ дан 1 December 2019 в 17:29
поделиться