【问题标题】:iterating over sorted treemap: java.util.ConcurrentModificationException遍历排序的树形图:java.util.ConcurrentModificationException
【发布时间】:2017-06-07 10:22:30
【问题描述】:

我有 Java 基础知识,目前正在编写基于 Java 的代码。

编辑:代码不是我写的

我正在遍历 Event 对象的排序树形图,并在尝试获取下一个元素时遇到此异常:

java.util.ConcurrentModificationException at java.util.TreeMap$PrivateEntryIterator.nextEntry(Unknown Source) at java.util.TreeMap$KeyIterator.next(Unknown Source)

我认为这应该是由于迭代器比较器合并了多个具有相同值的条目(参考这个question,但我不知道如何找到比较器中使用的键。对象Event 有很多参数(如id、时间等)但不确定哪个用于迭代器。

这里是相关代码部分(第二个SimEvent first = fit.next();中的异常):

    if (future.size() > 0) {
        List<SimEvent> toRemove = new ArrayList<SimEvent>();
        Iterator<SimEvent> fit = future.iterator();
        queue_empty = false;
        SimEvent first = fit.next();
        processEvent(first);
        future.remove(first);

        fit = future.iterator();

        // Check if next events are at same time...
        boolean trymore = fit.hasNext();
        while (trymore) {
            SimEvent next = fit.next();
            if (next.eventTime() == first.eventTime()) {
                processEvent(next);
                toRemove.add(next);
                trymore = fit.hasNext();
            } else {
                trymore = false;
            }
        }

        future.removeAll(toRemove);

    } else {...}

编辑:future类的大厅代码:

public class FutureQueue {

    /** The sorted set. */
    private final SortedSet<SimEvent> sortedSet = new TreeSet<SimEvent>();

    /** The serial. */
    private long serial = 0;

    /**
     * Add a new event to the queue. Adding a new event to the queue preserves the temporal order of
     * the events in the queue.
         * 
     * @param newEvent The event to be put in the queue.
     */
    public void addEvent(SimEvent newEvent) {
        newEvent.setSerial(serial++);
        sortedSet.add(newEvent);
    }

    /**
    * Add a new event to the head of the queue.
    * 
    * @param newEvent The event to be put in the queue.
    */
    public void addEventFirst(SimEvent newEvent) {
        newEvent.setSerial(0);
        sortedSet.add(newEvent);
    }

    /**
     * Returns an iterator to the queue.
     * 
     * @return the iterator
     */
     public Iterator<SimEvent> iterator() {
        return sortedSet.iterator();
     }

    /**
     * Returns the size of this event queue.
     * 
     * @return the size
     */
    public int size() {
        return sortedSet.size();
    }

    /**
     * Removes the event from the queue.
     * 
     * @param event the event
     * @return true, if successful
     */
    public boolean remove(SimEvent event) {
        return sortedSet.remove(event);
    }

    /**
     * Removes all the events from the queue.
     * 
     * @param events the events
     * @return true, if successful
     */
    public boolean removeAll(Collection<SimEvent> events) {
        return sortedSet.removeAll(events);
    }


    public void clear() {
        sortedSet.clear();
    }
}

关于如何继续调试此问题的任何建议?

【问题讨论】:

  • 能否分享future类的代码?
  • 为什么你有时使用 fit.next() 而不检查 fit.hasNext()?
  • @VasiliyVlasov:在问题编辑中完成
  • user7294900:我以这种方式获得此代码。在我得到异常之前,我已经检查了迭代器仍然有下一个元素。
  • 不清楚您是否得到 java.util.ConcurrentModificationException(在问题中)或 java.util.NoSuchElementException(在标题中)。

标签: java iterator treemap sortedset


【解决方案1】:

已编辑: 这是一个常见的错误。使用Iterator 遍历集合时,不能直接修改集合(添加或删除元素)。例如,删除必须通过 Iterator 本身完成。

正确的做法如下(不是完整的例子,只是为了说明问题):

Iterator<SimEvent> fit = future.iterator();
while (fit.hasNext()) {
    SimEvent event = fit.next();
    processEvent(event);
    fit.remove();
}

在您对集合进行迭代时,注意可能会添加到集合中或从集合中删除的其他线程。

【讨论】:

  • 抱歉,我看不到集合在哪里使用(仅在FutureQueue 类的removeAll 方法中)?问题是在我将其他类型的事件添加到队列之前,这段代码运行良好。
  • 你确定你已经发布了实际代码吗?抱歉问,但我正在查看 java.util.TreeMap$PrivateEntryIterator.nextEntry 的源代码,但看不到任何其他异常原因。您是否尝试在调试器中运行代码?
  • 是的。实际上,我正在开发其他人开发的模拟器,我正在使用 addEvent 方法将其他类型的事件添加到模拟器中其他地方的 future。我在调试器中运行代码,我可以看到 fit 有下一个元素但收到错误。
  • 如果您同时(在另一个线程中)在 future.iterator() 和 fit.next() 之间添加一个事件,这可能会出现问题,因为 addEvent() 会修改集合。这也可以解释为什么它有时有效,有时无效——这取决于方法调用的时间。
  • 我设法以不同的方式实现我的事件:我避免将它们直接添加到 future 类。感谢您提供宝贵的 cmets!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-09
  • 1970-01-01
  • 2012-04-08
  • 2013-05-10
相关资源
最近更新 更多