Java 并发修改异常
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1496180/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Concurrent Modification exception
提问by
I have this little piece of code and it gives me the concurrent modification exception. I cannot understand why I keep getting it, even though I do not see any concurrent modifications being carried out.
我有一小段代码,它给了我并发修改异常。我不明白为什么我一直得到它,即使我没有看到正在执行的任何并发修改。
import java.util.*;
public class SomeClass {
public static void main(String[] args) {
List<String> s = new ArrayList<>();
ListIterator<String> it = s.listIterator();
for (String a : args)
s.add(a);
if (it.hasNext())
String item = it.next();
System.out.println(s);
}
}
回答by Yuliy
You are not allowed to continue iterating over an iterator after the underlying list is modified. Here you create the iterator before adding a few items to s
, and then proceed to do a hasNext()
and a next()
on it after the additions, leading to the ConcurrentModificationException
修改基础列表后,不允许继续迭代迭代器。在这里,您在向 中添加一些项目之前创建了迭代器,然后在添加s
之后继续对其执行 ahasNext()
和 a next()
,从而导致ConcurrentModificationException
回答by leonm
From the JavaDoc:for ConcurrentModificatoinException: "it is not generally permssible for one thread to modify a Collection while another thread is iterating over it".
来自JavaDoc:对于 ConcurrentModificatoinException:“通常不允许一个线程修改集合,而另一个线程正在对其进行迭代”。
It simply means that if you still have an open iterator, you aren't allowed to modify the list because the iterator loop will break. Try moving ListIterator<String> it = s.listIterator();
till after the for loop.
这只是意味着如果您仍然有一个打开的迭代器,则不允许修改列表,因为迭代器循环会中断。尝试移动ListIterator<String> it = s.listIterator();
到 for 循环之后。
回答by Stephen C
I cannot understand why I keep getting it, even though I do not see any concurrent modifications being carried out.
我不明白为什么我一直得到它,即使我没有看到正在执行的任何并发修改。
Between creating the iterator and starting to use the iterator, you added arguments to the list that is to be iterated. This is a concurrent modification.
在创建迭代器和开始使用迭代器之间,您向要迭代的列表添加了参数。这是一个并发修改。
ListIterator<String> it = s.listIterator();
for (String a : args)
s.add(a); // concurrent modification here
if (it.hasNext())
String item = it.next(); // exception thrown here
Create the iterator AFTER you've finished adding elements to the list:
在您完成向列表添加元素后创建迭代器:
for (String a : args)
s.add(a);
ListIterator<String> it = s.listIterator();
if (it.hasNext())
String item = it.next();
回答by Pascal Thivent
To avoid the ConcurrentModificationException
, you should write your code like this:
为了避免ConcurrentModificationException
,您应该像这样编写代码:
import java.util.*;
public class SomeClass {
public static void main(String[] args) {
List<String> s = new ArrayList<String>();
for(String a : args)
s.add(a);
ListIterator<String> it = s.listIterator();
if(it.hasNext()) {
String item = it.next();
}
System.out.println(s);
}
}
A java.util.ListIterator
allows you to modify a list during iteration, but not between creating it and using it.
Ajava.util.ListIterator
允许您在迭代期间修改列表,但不能在创建它和使用它之间进行修改。
回答by jzarsuelo
If the above solutions doesn't work properly. You can use old for-loop for iterating a List at the same time adding new items. See the example below:
如果上述解决方案不能正常工作。您可以使用旧的 for 循环在添加新项目的同时迭代 List。请参阅下面的示例:
import java.util.*;
public class SomeClass {
public static void main(String[] args) {
ArrayList<AClass> aList = new ArrayList<AClass>(); // we will iterate this
// this will cause ConcurrentModificationException.
// Since we are iterating the list, at the same time modifying it.
/*for(AClass a: aList){
aList.add(someMethod(a));
}*/
// old fashion for-loop will help
int limit = aList.size();
for(int i=0; ctr<limit; ++i){
AClass a = aList.get(i);
aList.add(someMethod(a));
}
}
}
回答by Nurgul Alshyn
This didn't work:
这不起作用:
LinkedList<String> linkedList = new LinkedList<String>();
ListIterator listIterator = linkedList.listIterator();
linkedList.add("aa");
linkedList.add("bb");
This worked:
这有效:
LinkedList<String> linkedList = new LinkedList<String>();
linkedList.add("aa");
linkedList.add("bb");
ListIterator listIterator = linkedList.listIterator();
回答by ceph3us
to understand this lets look at source of HashMap implementation:
要理解这一点,让我们看看 HashMap 实现的来源:
public class HashMap<K, V> extends AbstractMap<K, V> implements Cloneable, Serializable{
which contains HashIterator as below:
其中包含 HashIterator 如下:
private abstract class HashIterator {
...
int expectedModCount = modCount;
...
HashMapEntry<K, V> nextEntry() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
....
}
every time you create a iterator:
每次创建迭代器时:
- a counter expectedModCountis created and is set to value of modCountas entry checkpoint
- modCount is incremented in cases of use put/get (add/remove)
- nextEntrymethod of iterator is checking this value with current modCount if they are different concurrent modification exception is throw
- 创建一个计数器expectedModCount并将其设置为modCount 的值 作为入口检查点
- modCount 在使用 put/get (add/remove) 的情况下增加
- 迭代器的nextEntry方法正在使用当前 modCount 检查此值,如果它们不同,则抛出并发修改异常
to avoid this u can:
为避免这种情况,您可以:
- convert map to an array (not recommended for large maps)
- use concurrency map or list classes (CopyOnWriteArrayList/ ConcurrentMap)
- lock map (this approach removes benefits of multithreading)
- 将地图转换为数组(不推荐用于大型地图)
- 使用并发映射或列表类(CopyOnWriteArrayList/ ConcurrentMap)
- 锁映射(这种方法消除了多线程的好处)
this will allow you to iterate and add or remove elements at the same time without rising an exception
这将允许您同时迭代和添加或删除元素而不会引发异常
Concurrency map/list iterator is a "weakly consistent" iterator that will never throw ConcurrentModificationException, and guarantees to traverse elements as they existed upon construction of the iterator, and may (but is not guaranteed to) reflect any modifications subsequent to construction.
并发映射/列表迭代器是一个“弱一致性”迭代器,它永远不会抛出 ConcurrentModificationException,并保证遍历在构造迭代器时存在的元素,并且可能(但不保证)反映构造之后的任何修改。
回答by Ravindra babu
Have a look at oracle documentationpage.
看看oracle文档页面。
public class ConcurrentModificationException
extends RuntimeException
This exception may be thrown by methods that have detected concurrent modification of an object when such modification is not permissible
Note that this exception does not always indicate that an object has been concurrently modified by a different thread. If a single thread issues a sequence of method invocations that violates the contract of an object, the object may throw this exception. For example, if a thread modifies a collection directly while it is iterating over the collection with a fail-fast iterator, the iterator will throw this exception.
当不允许此类修改时,检测到对象的并发修改的方法可能会抛出此异常
请注意,此异常并不总是表示对象已被不同线程同时修改。如果单个线程发出一系列违反对象约定的方法调用,则该对象可能会抛出此异常。例如,如果线程在使用快速失败迭代器迭代集合时直接修改集合,则迭代器将抛出此异常。
In your case, you have modified the collection after creating the iterator and hence you have encountered the exception.
在您的情况下,您在创建迭代器后修改了集合,因此遇到了异常。
If you change your code as per Stephen Canswer, you won't get this error.
如果您按照Stephen C 的回答更改代码,则不会出现此错误。
回答by Najeeb Arif
ConcurrentModificationException may arise in both single threaded environment and multi-threaded environment. The main catch is that all the general purpose iterators (like the one used in ArrayList) are all FailFast iterators, which fails when we try to modify one list if one iterator is already iterating over it. Solution - > Use CopyOnWriteArrayList if such scenario is needed by the requirement rather than using ArrayList.
ConcurrentModificationException可能出现在单线程环境和多线程环境中。主要问题是所有通用迭代器(如 ArrayList 中使用的迭代器)都是FailFast 迭代器,当我们尝试修改一个列表时,如果一个迭代器已经在迭代它,它就会失败。解决方案 - > 如果需求需要这种场景,请使用 CopyOnWriteArrayList 而不是使用 ArrayList。
For a complete demo for this, below mentioned code can be used. We just need to change the implementation from CopyOnWriteArrayList to ArrayList.
对于一个完整的演示,可以使用下面提到的代码。我们只需要将实现从 CopyOnWriteArrayList 更改为 ArrayList。
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* @author narif
*
*/
public class TestApp {
/**
* @param args
*/
public static void main(String[] args) {
List<String> testList = new ArrayList<>();
testList.add("abc");
testList.add("abc");
testList.add("abc");
testList.add("abc");
testList.add("abc");
testList.add("abc");
testList.add("abc");
testList.add("abc");
testList.add("abc");
testList.add("abc");
testList.add("abc");
testList.add("abc");
testList.add(6, "abcAtindex6");
int size = testList.size();
System.out.println("The Current List (ArrayList) is: " + testList);
System.out.println("The size of the List (ArrayList) is: " + size);
/* Comment the below lines to get the ConcurrentModificationException */
testList = new CopyOnWriteArrayList<>(testList);
for (String value : testList) {
System.out.println("The Value from ForEach Loop is: " + value);
/*
* Concurrent modification is happening here
* One iterator is iterating over the list while we are trying to add new values to
* the list so the results of the iteration are undefined under these circumstances.
* So teh fail fast iterators will fail and will throw the ConcurrentModificationException.
*/
testList.add("valueFromForLoop");
testList.add("anotherValueFromForEachLoop");
}
Iterator<String> it = testList.iterator();
while (it.hasNext()) {
String abc = it.next();
System.out.println(abc);
testList.add("Value from Iterator1");
testList.add("Value from Iterator2");
testList.add("Value from Iterator3");
testList.add("Value from Iterator4");
}
System.out.println("Did the modificationa and all after conevrting the ArrayList to CopyOnWriteArrayList.");
System.out.println("Calling the method to get the new List..");
testList = new CopyOnWriteArrayList<>(getTheList(testList));
for (String value : testList) {
System.out.println("The value returned from method is : " + value);
}
}
private static List<String> getTheList(List<String> pList) {
List<String> list = new CopyOnWriteArrayList<>(pList);
int i = 0;
for (String lValue : list) {
System.out.println("The list Passed is " + list);
i++;
list.add("localVaueFromMethod" + i);
list.removeAll(pList);
}
return list;
}
}
For more inifo follow this link this may be helpful alot ConcurrentModificationException Java Docs
有关更多信息,请点击此链接,这可能会很有帮助ConcurrentModificationException Java Docs