Search code examples
javaiteratortreemapsortedset

iterating over sorted treemap: java.util.ConcurrentModificationException


I have basic knowledge in Java and working currently on a Java based code.

EDIT: I didn't write the code

I am iterating over a sorted treemap of Event Objects and getting this exception when I am trying to get the next element:

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

I think this should be due to the existence of mutiple entries with same value that are merged by the iterator comparator (be refering to this question, but I don't know how to find the keys used in the comparator. The object Event has many parameters (like id, time, etc)but not sure which one is used for the iterator.

Here is the related code portion (exception in the second 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 {...}

EDIT: The hall code of future class:

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

Any suggestion on how to proceed to debug this problem?


Solution

  • EDITED: This is a common mistake. You cannot modify a collection directly (add or remove elements) when iterating through the collection using an Iterator. Removal, for example, must be done via the Iterator itself.

    The correct way to do it is as follows (not a complete example, just to illustrate the point):

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

    Watch for other threads that might add to or remove from the collection while you are iterating through it.