別のスレッドが でイテレータを使用してremoveListener()
いるときに、次のコードで を呼び出すと がスローされるのはなぜですか?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
}
}
}
}
私の理解では、 in を使用synchronized (synchronizedListeners)
しているため、 infireEvent()
を呼び出す他のスレッドをブロックする必要がremoveListener()
あります。 in の反復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();
}