问题
I have a class which stores data and gets called from many threads. It fails with a ConcurrentModificationException although every access to my Set is synchronized.
How can this happen? The synchronized should make sure that my Set is not changed while it is iterated...
Here are all functions from my class that access the Set...
Can anyone tell me what is going wrong here?
private final Object mListenerLock = new Object();
private final Set<IRetainerBaseListener> mListeners = new HashSet<IRetainerBaseListener>();
protected final void register(IRetainerBaseListener listener)
{
synchronized (mListenerLock)
{
mListeners.add(listener);
}
}
protected final boolean unregister(IRetainerBaseListener listener)
{
synchronized (mListenerLock)
{
return mListeners.remove(listener);
}
}
private final void onObjectAdded(RKey key, Object data)
{
synchronized (mListenerLock)
{
Iterator<IRetainerBaseListener> it = mListeners.iterator();
while (it.hasNext())
{
IRetainerBaseListener listener = it.next();
/* EDIT */
/* I'm not changing the Set in here, never!!! */
// I can't insert the if's, but I just check the interface class
// and call one of the following methods:
((IRetainerListener) listener).onRetainerDataAdded(key, data);
// or
((IRetainerSingleKeyListener) listener).onRetainerDataAdded(data);
}
}
}
回答1:
It's not a problem of thread safety.
You are removing items while iterating on your collection. This is only possible using an iterator.
/*
* *it* does not appreciate that you removed elements
* in another way than it.remove();
* The iterator must do the add/remove operations itself
* to guarantee that it will not break the iteration.
*/
while (it.hasNext()) {
IRetainerBaseListener listener = it.next();
...
}
回答2:
Synchronized is ensuring that no other thread is executing while also trying to hold a 'lock' during that operations.
Example:
Thread A: synchronized(mListenerLock) { doSomething; }
Thread B:
synchronized(mListenerLock) { doSomething; }
This way either A or B is doing something. One have to wait for the other to release the binary 'lock' of mListenerLock.
In your case you use the very same thread to perform your actions. So you get the concurrent modification exception because you alter the state of the list (removing objects) while also iterating it.
ConcurrentModificationException does not refer to a concurrency problem in terms of threads. It is just stating that while doing one thing with a list (or related objects) your program does some other things that prevents things from working as intended. It is a (defensive) safety mechanism to prevent common bugs to happen unnoticed.
来源:https://stackoverflow.com/questions/19138161/how-can-a-synchronized-iteration-on-a-set-fail-with-a-concurrentmodificationexce