java - 在迭代时更新 PriorityQueue

标签 java android priority-queue

我需要根据 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/

相关文章:

c++ - 优先队列,重载少操作

java - 线程中的异步回调

java - Groovy 按更多标准分组

android - 尝试在文本中嵌套 View 时出现 React Native Android 错误

android - 将表单数据发送到电子邮件

c++ - 从 std::heap 中间移除一个元素

java - Scala 是否对小型集合使用特殊实现?

java - 将变量传递给java进程

Android gradle 无法解析 : play-services-basement

c++ - 如何使用指针为 c++ priority_queue 实现排序方法