0

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?

Betty
  • 237
  • 6
  • 16

1 Answers1

0

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.

vempo
  • 3,093
  • 1
  • 14
  • 16
  • Sorry, I don't see where a collection is used (only in `removeAll` method of `FutureQueue` class)? The thing is that this code is working fine before I add other types of events to the queue. – Betty Jun 07 '17 at 11:06
  • Are you sure you've posted the actual code? Sorry for asking, but I'm looking at the source code of java.util.TreeMap$PrivateEntryIterator.nextEntry and can't see any other reason for the exception. Did you try to run the code in a debugger? – vempo Jun 07 '17 at 12:01
  • Yes it is. Actually I am working on a simulator developed by other people, I am adding other types of events to `future` elsewhere in the simulator using the `addEvent` method. I run the code in the debugger and I can see that `fit` has next element but getting the error. – Betty Jun 07 '17 at 12:17
  • I would also check if equals() and hashCode() of SimEvent are implemented correctly, and two equal SimEvent object always have the same hash code. https://stackoverflow.com/questions/2265503/why-do-i-need-to-override-the-equals-and-hashcode-methods-in-java – vempo Jun 07 '17 at 12:19
  • Can you post the code that initializes future? Do you add to/remove from future in a parallel thread somewhere? The point is that an iterator becomes invalid if someone modifies its enclosing collection after the iterator was created. – vempo Jun 07 '17 at 12:24
  • Yes, I am adding/modifying `future` in another class. For certain adds, it is working fine. `future` is declared this way in `Sim` class: `protected static FutureQueue future;` `future = new FutureQueue();` In the basic version of the code, events are added to `future` using different methods of `Sim` class. – Betty Jun 07 '17 at 12:48
  • 1
    This might be a problem if you concurrently (in another thread) add an event between future.iterator() and fit.next(), because addEvent() modifies the collection. This could also explain why it sometimes work and sometimes doesn't - it depends on the timing of method calls. – vempo Jun 07 '17 at 12:55
  • This could be a reason, but the error is happening inside the `while(trymore)` loop, so It means at the time I assign `future` iterator in `fit`, even if `future` is modified that should not impact `fit`. Will the value of `fit` change even if I am not updating it inside the loop? – Betty Jun 07 '17 at 13:37
  • fit (Iterator) is impacted whenever the future (TreeSet) it was received from is modified. See above. – vempo Jun 07 '17 at 13:42
  • 1
    I managed to implement my events in a different way: I avoided adding them directly to `future` class. Thank you for the valuable comments! – Betty Jun 19 '17 at 11:25