Reputation: 1462
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
Upvotes: 2
Views: 3471
Reputation: 3809
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.
Upvotes: 5
Reputation: 1216
That's because you are trying to access to it concurrently, and ArrayList
it not synchronized
.
You can use java.util.Vector
which is synchronized or make ArrayList
synchronized 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
}
Upvotes: -1