简体   繁体   English

迭代ArrayList时Java ConcurrentModificationException

[英]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.

相关问题 迭代ArrayList时出现ConcurrentModificationException <Integer> - ConcurrentModificationException when iterating through an ArrayList <Integer> ArrayList删除时出现Java ConcurrentModificationException - Java ConcurrentModificationException when on ArrayList Deletion 迭代并从 ArrayList 中删除元素时如何避免 java.util.ConcurrentModificationException - How to avoid java.util.ConcurrentModificationException when iterating through and removing elements from an ArrayList 如何在迭代时仅避免ArrayList中的ConcurrentModificationException? - How do I avoid ConcurrentModificationException in ArrayList ONLY when iterating? 在LinkedList上迭代时出现ConcurrentModificationException - ConcurrentModificationException when iterating on LinkedList java ArrayList中的ConcurrentModificationException - ConcurrentModificationException in java ArrayList 迭代Arraylist时的ConcurrentModificationException(不删除) - ConcurrentModificationException while iterating through Arraylist (not removing) 尝试在 Java 中使用多个线程对 Arraylist 的数量求和时出现 ConcurrentModificationException - ConcurrentModificationException when trying to sum numbers of an Arraylist using multiple threads in Java 迭代map时出现ConcurrentModificationException - ConcurrentModificationException when iterating over map Java-同步的ArrayList仍然ConcurrentModificationException - Java - synchronized ArrayList still ConcurrentModificationException
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM