java 如何调试 ConcurrentModificationException?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/840165/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to debug ConcurrentModificationException?
提问by Dani
I encountered ConcurrentModificationException and by looking at it I can't see the reason why it's happening; the area throwing the exception and all the places modifying the collection are surrounded by
我遇到了 ConcurrentModificationException 并且通过查看它我看不出它发生的原因;抛出异常的区域和所有修改集合的地方都被包围
synchronized (this.locks.get(id)) {
...
} // locks is a HashMap<String, Object>;
I tried to catch the the pesky thread but all I could nail (by setting a breakpoint in the exception) is that the throwing thread owns the monitor while the other thread (there are two threads in the program) sleeps.
我试图抓住讨厌的线程,但我所能确定的(通过在异常中设置断点)是抛出线程拥有监视器,而另一个线程(程序中有两个线程)休眠。
How should I proceed? What do you usually do when you encounter similar threading issues?
我应该如何进行?当您遇到类似的线程问题时,您通常会怎么做?
回答by Adam Paynter
It may have nothing to do with the synchronization block. ConcurrentModificationExceptions often occur when you're modifying a collection while you are iterating over its elements.
它可能与同步块无关。ConcurrentModificationException当您在迭代其元素时修改集合时,通常会发生 s。
List<String> messages = ...;
for (String message : messages) {
// Prone to ConcurrentModificationException
messages.add("A COMPLETELY NEW MESSAGE");
}
回答by Peter Lawrey
Similar to a previous post, you can get the same issue if you delete an entry. e.g.
与之前的帖子类似,如果删除条目,也会遇到相同的问题。例如
for(String message : messages) {
if (condition(message))
messages.remove(message);
}
Another common example is cleaning up a Map.
另一个常见的例子是清理 Map。
This particular problem can be resolved using an Iterator explicitly.
这个特殊的问题可以明确地使用迭代器来解决。
for(Iterator<String> iter = messages.iterator(); iter.hasNext();) {
String message = iter.next();
if (condition(message))
iter.remove(); // doesn't cause a ConcurrentModificationException
}
回答by Béatrice Cassistat
Sometime your application may be complex too complex and some functions may have too much side effect. Also, maybe another thread is really doing something wrong with that list and you can't find where easily.
有时您的应用程序可能过于复杂,某些功能可能会产生过多的副作用。此外,也许另一个线程确实对该列表有问题,您无法轻松找到哪里。
For my own problem, I've write my own list system that delegates another list and, once locked, all other modifications throws ConcurrentModificationException, so the bad modification instruction will get at output with the exception. It can also detect errors described above.
对于我自己的问题,我编写了自己的列表系统来委托另一个列表,一旦锁定,所有其他修改都会抛出 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));
}
}
Simply use it like this :
只需像这样使用它:
List list = new LockableList(new ArrayList(...));
list.setLocked(true);
for (E e : list.iterator())
{ ... }
list.setLocked(false);
Hope it may help someone else.
希望它可以帮助别人。
回答by iftee
if you need to delete few elements from your list. You can maintain another list like elements to be removed. And finally call removeAll(collection). Of course this is not good for huge data.
如果您需要从列表中删除几个元素。您可以维护另一个列表,例如要删除的元素。最后调用 removeAll(collection)。当然,这对于大数据来说是不利的。
回答by JanDasWiesel
Having had to deal with similar issues I wrote a small helper to debug concurrent access situations on certain objects (sometimes using a debugger modifies the runtime behavior so much that the issue does not occur). The approach is similar to the one Francois showed, but a bit more generic. Maybe it helps someone: http://code.google.com/p/kongcurrent/
不得不处理类似的问题后,我编写了一个小助手来调试某些对象上的并发访问情况(有时使用调试器会修改运行时行为,以至于问题不会发生)。该方法类似于 Francois 展示的方法,但更通用一些。也许它可以帮助某人:http: //code.google.com/p/kongcurrent/
回答by Lucas Lindstr?m
It's common to receive a ConcurrentModificationException when modifying a dynamic list while iterating over it (in a foreach-loop for example). You may want to make sure you're not doing that anywhere.
在迭代动态列表时(例如在 foreach 循环中)修改动态列表时,通常会收到 ConcurrentModificationException。你可能想确保你没有在任何地方这样做。

