2

I get ConcurrentModificationException when iterating an ArrayList and adding objects to a secondary ArrayList. I don't really know why because I'm not editing the list that I'm iterating through.

This happens in two parts of my code. These are the codes.

EDIT - Code 1:

public static ConcurrentHashMap<Long, ArrayList<HistoricalIndex>> historicalIndexesMap = new ConcurrentHashMap<Long, ArrayList<HistoricalIndex>>();

ArrayList<HistoricalIndex> historicalIndexList = IndexService.historicalIndexesMap.get(id);
List<Double> tmpList = new ArrayList<Double>();
for(HistoricalIndex hi : historicalIndexList){ //EXCEPTION HERE
    if((System.currentTimeMillis()-hi.getTimestamp()) >= ONE_MINUTE){
        tmpList.add(hi.getIndex());
    }
}

In Code 1 above, should I copy the historicalIndexList like this:

ArrayList<HistoricalIndex> historicalIndexList = new ArrayList<HistoricalIndex>(IndexService.historicalIndexesMap.get(id));

instead of doing this: ?

ArrayList<HistoricalIndex> historicalIndexList = IndexService.historicalIndexesMap.get(id);

Code 2:

List<Double> tmpList = new ArrayList<Double>();
for(HistoricalIndex hi : list){ //EXCEPTION HERE
    tmpList.add(hi.getIndex());
}

Does anyone have a clue why this happens?

Stacktrace:

21:19:50,426 ERROR [stderr] (pool-9-thread-6) java.util.ConcurrentModificationException
21:19:50,429 ERROR [stderr] (pool-9-thread-6)   at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)
21:19:50,432 ERROR [stderr] (pool-9-thread-6)   at java.util.ArrayList$Itr.next(ArrayList.java:831
6
  • What type is list and where do you define it? Commented Jan 7, 2015 at 11:53
  • 2
    Are you sure the historicalIndexList is not modified anywhere by any other thread? Commented Jan 7, 2015 at 11:53
  • 2
    Typical a concurrency issue / race conditions. Commented Jan 7, 2015 at 11:54
  • @nfechner list is of type ArrayList and it's defined in a ConcurrentHasmap. Each thread that uses this list copies it to a temporary list after getting it from the hashmap. Commented Jan 7, 2015 at 12:00
  • Add a logging statement inside the loops and check the thread printed out Commented Jan 7, 2015 at 12:09

2 Answers 2

5

Let's take a brief look at what causes a ConcurrentModificationException. The ArrayList maintains internally a modification count value which is just an integer which gets incremented every time there is a modification to the list. When an iterator is created it takes a 'snapshot' of this value. Then, every time the iterator is used it checks that its copy of this value still matches the array's own copy. If it does not it throws the exception.

This means that for a ConcurrentModificationException to occur there must have been some modification to the ArrayList after you first created the iterator (i.e. after the for() statement was first executed but before it ends). As your for() loop is not modifying the ArrayList it means that some other thread must be changing the array while you are iterating through it.

EDIT: In reply to your edit, yes you should copy the array if other threads would be changing it. You could even do something like:

for(HistoricalIndex hi: new ArrayList<HistoricalIndex>(historicalIndexList))

... to copy the list when starting your loop.

To sum up, a ConcurrentModificationException has nothing to do with what we normally think of as concurrency problems. You can quite easily get one in a single thread by modifying an array within an iterator loop other than via the iterator's remove() method. 'Concurrent' in this case means iteration and modification are occurring concurrently - whether in the same or different threads.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for the fast answer. I'll try copying it.
-1

That's because you are trying to access to it concurrently, and ArrayList it not synchronized.
You can use java.util.Vectorwhich is synchronized or make ArrayListsynchronized doing:

Collections.synchronizedList(new ArrayList(...)); 

As @izca comments, to avoid cocurrent modification, you should put the list created in a synchronized block:

List<T> myList = Collections.synchronizedList(new ArrayList<T>(...)); 
synchronized(myList) { 
    // to modify elements in myList
}

1 Comment

A Vector or a synchronized list only synchronizes the methods. It would still allow modifying the List while an iteration is in progress, and it would result in the same ConcurrentModificationException.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.