我遇到了ConcurrentModificationException,通过查看它我看不出它为什么会发生的原因;抛出异常的区域和修改集合的所有区域都被
包围synchronized (this.locks.get(id)) {
...
} // locks is a HashMap<String, Object>;
我试图抓住那个讨厌的线程,但我所能指出的(通过在异常中设置断点)是抛出线程拥有监视器而另一个线程(程序中有两个线程)睡眠。
我该怎么办?当遇到类似的线程问题时,您通常会做什么?
答案 0 :(得分:30)
它可能与同步块无关。当您在迭代其元素时修改集合时,经常会出现ConcurrentModificationException
。
List<String> messages = ...;
for (String message : messages) {
// Prone to ConcurrentModificationException
messages.add("A COMPLETELY NEW MESSAGE");
}
答案 1 :(得分:12)
与上一篇文章类似,如果删除条目,则可能会遇到同样的问题。 e.g。
for(String message : messages) {
if (condition(message))
messages.remove(message);
}
另一个常见的例子是清理地图。
可以使用Iterator明确解决此特定问题。
for(Iterator<String> iter = messages.iterator(); iter.hasNext();) {
String message = iter.next();
if (condition(message))
iter.remove(); // doesn't cause a ConcurrentModificationException
}
答案 2 :(得分:5)
有时您的应用程序可能过于复杂而某些功能可能会产生太多副作用。另外,也许另一个线程确实对该列表做错了,你无法轻易找到。
对于我自己的问题,我编写了自己的列表系统,委托另一个列表,一旦锁定,所有其他修改抛出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);
希望它可以帮助别人。
答案 3 :(得分:4)
如果您需要从列表中删除少量元素。您可以维护另一个列表,例如要删除的元素。最后调用removeAll(collection)。当然,这对于大量数据来说并不好。
答案 4 :(得分:2)
由于不得不处理类似的问题,我编写了一个小助手来调试某些对象的并发访问情况(有时使用调试器会修改运行时行为以至于不会发生问题)。这种方法类似于弗朗索瓦所展示的方法,但更为通用。也许它有助于某人:http://code.google.com/p/kongcurrent/
答案 5 :(得分:1)
在迭代它时修改动态列表时会收到ConcurrentModificationException(例如,在foreach循环中)。您可能希望确保在任何地方都不这样做。