如何使用ConcurrentModificationException对Set上的同步迭代失败

时间:2013-10-02 13:34:30

标签: java iterator synchronized

我有一个存储数据的类,并从多个线程调用。虽然对ConcurrentModificationException的每次访问都是同步的,但Set失败了。

这怎么可能发生? synchronized应该确保我的Set在迭代时不会被更改...

以下是我班级中访问Set ...

的所有功能

谁能告诉我这里出了什么问题?

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);

        }
    }
}

2 个答案:

答案 0 :(得分:4)

这不是线程安全的问题。

您在迭代集合时删除项目。这只能使用迭代器

 /*
  * *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();
   ...
 }

答案 1 :(得分:0)

同步确保没有其他线程正在执行,同时还试图在该操作期间保持“锁定”。

示例:

线程A: synchronized(mListenerLock){    做一点事; }

主题B:

synchronized(mListenerLock){    做一点事; }

这样A或B都在做某事。必须等待另一个释放mListenerLock的二进制“锁定”。

在您的情况下,您使用相同的线程来执行您的操作。因此,您可以获得并发修改异常,因为您可以更改列表的状态(删除对象),同时也可以迭代它。

ConcurrentModificationException并未引用线程方面的并发问题。它只是声明在使用列表(或相关对象)执行一项操作时,程序会执行一些其他操作,以防止事情按预期工作。它是一种(防御性)安全机制,可以防止常见错误被忽视。