[英]Java ConcurrentModificationException when iterating ArrayList
I get ConcurrentModificationException
when iterating an ArrayList
and adding objects to a secondary ArrayList
.迭代ArrayList
并将对象添加到辅助ArrayList
时,我得到ConcurrentModificationException
。 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:编辑 -代码 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:在上面的代码 1 中,我应该像这样复制历史索引列表:
ArrayList<HistoricalIndex> historicalIndexList = new ArrayList<HistoricalIndex>(IndexService.historicalIndexesMap.get(id));
instead of doing this: ?而不是这样做:
ArrayList<HistoricalIndex> historicalIndexList = IndexService.historicalIndexesMap.get(id);
Code 2:代码 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
Let's take a brief look at what causes a ConcurrentModificationException.让我们简单看一下导致 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. ArrayList 在内部维护一个修改计数值,它只是一个整数,每次对列表进行修改时都会递增。 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 (ie after the for() statement was first executed but before it ends).这意味着要发生 ConcurrentModificationException 必须在您第一次创建迭代器之后(即在 for() 语句第一次执行之后但在它结束之前)对 ArrayList 进行了一些修改。 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.由于您的 for() 循环没有修改 ArrayList,这意味着在您遍历数组时,其他线程必须更改数组。
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.综上所述,ConcurrentModificationException 与我们通常认为的并发问题无关。 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.通过修改迭代器循环中的数组而不是通过迭代器的 remove() 方法,您可以很容易地在单个线程中获得一个。 'Concurrent' in this case means iteration and modification are occurring concurrently - whether in the same or different threads.在这种情况下,“并发”意味着迭代和修改同时发生——无论是在相同还是不同的线程中。
That's because you are trying to access to it concurrently, and ArrayList
it not synchronized
.那是因为您试图同时访问它,而ArrayList
它没有synchronized
。
You can use java.util.Vector
which is synchronized or make ArrayList
synchronized doing:您可以使用同步的java.util.Vector
或使ArrayList
同步:
Collections.synchronizedList(new ArrayList(...));
As @izca comments, to avoid cocurrent modification, you should put the list created in a synchronized block:正如@izca 评论的那样,为避免并发修改,您应该将创建的列表放在同步块中:
List<T> myList = Collections.synchronizedList(new ArrayList<T>(...));
synchronized(myList) {
// to modify elements in myList
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.