为什么当另一个线程正在使用迭代器时removeListener()
,以下代码中的调用会抛出 a ?ConcurrentModificationException
fireEvent()
public class MyClass {
private Set<Object> synchronizedListeners;
public MyClass() {
synchronizedListeners = Collections.synchronizedSet(
new LinkedHashSet<Object>());
}
public void addListener(Object listener) {
synchronizedListeners.add(listener);
}
public synchronized void removeListener(Object listener) {
synchronizedListeners.remove(listener);
}
public void fireEvent() {
synchronized (synchronizedListeners) {
for (Object listener : synchronizedListeners) {
// do something with listener
}
}
}
}
据我了解,由于我使用的是synchronized (synchronizedListeners)
in fireEvent()
,这应该阻止任何其他调用 的线程removeListener()
,直到迭代fireEvent()
完成,此时从该 Set 中删除一个元素应该是安全的。但情况似乎并非如此。我究竟做错了什么?
可能相关:Java 同步块与 Collections.synchronizedMap
编辑:有人指出我不必要地同步了 removeListener() 方法。所以我尝试了这个版本:
public void removeListener(Object listener) {
synchronizedListeners.remove(listener);
}
但仍然得到同样的错误。
编辑 2:正如 assylias 所指出的,问题在上面的代码中不可见。我是从导致错误的块中removeListener()
的 for 循环内部调用的。synchronized (synchronizedListeners)
在这种情况下我最终使用的修复是从另一个线程中删除侦听器:
public void removeListener(final Object listener) {
new Thread() {
@Override
public void run() {
synchronizedListeners.remove(listener);
}
}.start();
}