我需要根据 ID 更新 PriorityQueue 中的一些固定优先级元素。我认为这是一个很常见的场景,下面是一个示例 fragment (Android 2.2):
for (Entry e : mEntries) {
if (e.getId().equals(someId)) {
e.setData(newData);
}
}
然后我将 Entry 设置为“不可变的”(没有 setter 方法),以便创建一个新的 Entry 实例并由 setData() 返回。我将我的方法修改为:
for (Entry e : mEntries) {
if (e.getId().equals(someId)) {
Entry newEntry = e.setData(newData);
mEntries.remove(e);
mEntries.add(newEntry);
}
}
代码似乎工作正常,但有人指出在迭代队列时修改队列是个坏主意:它可能会抛出 ConcurrentModificationException 并且我需要将要删除的元素添加到 ArrayList 并删除稍后。他没有解释为什么,这对我来说看起来很开销,但我在互联网上找不到任何具体的解释。
(This post 类似,但优先级可以改变,这不是我的情况)
任何人都可以阐明我的代码有什么问题,我应该如何更改它以及 - 最重要的 - 为什么?
谢谢, 涟漪
PS:一些实现细节...
PriorityQueue<Entry> mEntries = new PriorityQueue<Entry>(1, Entry.EntryComparator());
与:
public static class EntryComparator implements Comparator<Entry> {
public int compare(Entry my, Entry their) {
if (my.mPriority < their.mPriority) {
return 1;
}
else if (my.mPriority > their.mPriority) {
return -1;
}
return 0;
}
}
最佳答案
此代码在 PriorityQueue 的 Java 6 实现中:
private class Itr implements Iterator<E> {
/**
* The modCount value that the iterator believes that the backing
* Queue should have. If this expectation is violated, the iterator
* has detected concurrent modification.
*/
private int expectedModCount = modCount;
public E next() {
if(expectedModCount != modCount) {
throw new ConcurrentModificationException();
}
}
}
现在,为什么这段代码在这里?如果您查看 Javadoc for ConcurrentModificationException如果在迭代完成之前对基础集合进行了修改,您会发现迭代器的行为是未定义的。因此,许多集合都实现了这种 modCount
机制。
修复代码
您需要确保不在循环中修改代码。如果您的代码是单线程的(看起来是这样),那么您只需按照同事的建议进行操作,然后将其复制到列表中以供以后包含。此外,使用 Iterator.remove()记录方法以防止 ConcurrentModificationExceptions。一个例子:
List<Entry> toAdd = new ArrayList<Entry>();
Iterator it = mEntries.iterator();
while(it.hasNext()) {
Entry e = it.next();
if(e.getId().equals(someId)) {
Entry newEntry = e.setData(newData);
it.remove();
toAdd.add(newEntry);
}
}
mEntries.addAll(toAdd);
关于java - 在迭代时更新 PriorityQueue,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7105938/