How can a synchronized iteration on a Set fail with a ConcurrentModificationException [duplicate]

橙三吉。 提交于 2019-12-24 15:42:57

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!