我有一个存储数据的类,并从多个线程调用。虽然对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);
}
}
}
答案 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并未引用线程方面的并发问题。它只是声明在使用列表(或相关对象)执行一项操作时,程序会执行一些其他操作,以防止事情按预期工作。它是一种(防御性)安全机制,可以防止常见错误被忽视。