Java 并发修改异常
我有这段代码,它给了我并发修改异常。我不明白为什么我一直得到它,即使我没有看到任何并发的修改正在进行Java 并发修改异常,java,concurrentmodification,Java,Concurrentmodification,我有这段代码,它给了我并发修改异常。我不明白为什么我一直得到它,即使我没有看到任何并发的修改正在进行 import java.util.*; public class SomeClass { public static void main(String[] args) { List<String> s = new ArrayList<>(); ListIterator<String> it = s.listIterat
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);
}
}
import java.util.*;
公共类{
公共静态void main(字符串[]args){
列表s=新的ArrayList();
ListIterator it=s.ListIterator();
for(字符串a:args)
s、 添加(a);
if(it.hasNext())
String item=it.next();
系统输出打印项次;
}
}
修改基础列表后,不允许继续在迭代器上迭代。在这里,您在向s
添加一些项目之前创建迭代器,然后在添加之后继续对其执行hasNext()
和next()
,从而导致for ConcurrentModificationException的ConcurrentModificationException
:“通常不允许一个线程在另一个线程迭代集合时修改集合”
这只是意味着,如果仍然有一个打开的迭代器,则不允许修改列表,因为迭代器循环将中断。请尝试将ListIterator It=s.ListIterator();
移动到for循环之后
我不明白为什么我一直得到它,即使我没有看到任何并发的修改正在进行
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);
}
}
在创建迭代器和开始使用迭代器之间,您向要迭代的列表添加了参数。这是一个并发修改
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
ListIterator it=s.ListIterator();
for(字符串a:args)
s、 在此处添加(a);//并发修改
if(it.hasNext())
String item=it.next();//此处引发异常
在完成向列表中添加元素后创建迭代器:
for (String a : args)
s.add(a);
ListIterator<String> it = s.listIterator();
if (it.hasNext())
String item = it.next();
for(字符串a:args)
s、 添加(a);
ListIterator it=s.ListIterator();
if(it.hasNext())
String item=it.next();
为了避免出现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);
}
}
import java.util.*;
公共类{
公共静态void main(字符串[]args){
列表s=新的ArrayList();
for(字符串a:args)
s、 添加(a);
ListIterator it=s.ListIterator();
如果(it.hasNext()){
String item=it.next();
}
系统输出打印项次;
}
}
java.util.ListIterator
允许您在迭代过程中修改列表,但不能在创建列表和使用列表之间进行修改。如果上述解决方案无法正常工作。您可以使用旧for循环在添加新项的同时迭代列表。请参见下面的示例:
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));
}
}
}
import java.util.*;
公共类{
公共静态void main(字符串[]args){
ArrayList aList=new ArrayList();//我们将迭代此
//这将导致ConcurrentModificationException。
//因为我们正在迭代列表,同时修改它。
/*对于(a类:列表){
添加(方法(a));
}*/
//旧的循环方式会有所帮助
int limit=aList.size();
对于(int i=0;ctr这不起作用:
LinkedList<String> linkedList = new LinkedList<String>();
ListIterator listIterator = linkedList.listIterator();
linkedList.add("aa");
linkedList.add("bb");
LinkedList LinkedList=新建LinkedList();
ListIterator ListIterator=linkedList.ListIterator();
linkedList.add(“aa”);
linkedList.add(“bb”);
这起到了作用:
LinkedList<String> linkedList = new LinkedList<String>();
linkedList.add("aa");
linkedList.add("bb");
ListIterator listIterator = linkedList.listIterator();
LinkedList LinkedList=新建LinkedList();
linkedList.add(“aa”);
linkedList.add(“bb”);
ListIterator ListIterator=linkedList.ListIterator();
要理解这一点,让我们看看HashMap实现的源代码:
public class HashMap<K, V> extends AbstractMap<K, V> implements Cloneable, Serializable{
公共类HashMap扩展了AbstractMap实现了可克隆、可序列化{
其中包含哈希迭代器,如下所示:
private abstract class HashIterator {
...
int expectedModCount = modCount;
...
HashMapEntry<K, V> nextEntry() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
....
}
私有抽象类哈希迭代器{
...
int expectedModCount=modCount;
...
HashMapEntry nextEntry(){
if(modCount!=预期的modCount)
抛出新的ConcurrentModificationException();
....
}
每次创建迭代器时:
- 将创建一个计数器expectedModCount,并将其设置为modCount值作为入口检查点
- 在使用put/get(添加/删除)的情况下,modCount会增加
- nextEntry迭代器的方法正在使用当前modCount检查此值,如果它们不同,则会引发并发修改异常
要避免这种情况,您可以:
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));
}
}
}
- 将贴图转换为数组(不建议用于大型贴图)
- 使用并发映射或列表类(/)
- 锁映射(这种方法消除了多线程的优点)
这将允许您同时迭代和添加或删除元素,而不会引发异常
并发映射/列表迭代器是一个“弱一致”迭代器,它将
永远不要抛出ConcurrentModificationException,并保证
遍历迭代器构造时存在的元素,
并且可能(但不保证)反映任何修改
施工之后
看看oracle页面
当对象的并发修改不允许时,检测到该修改的方法可能会引发此异常
请注意,此异常并不总是表示对象已被其他线程并发修改。如果单个线程发出的方法调用序列违反了对象的约定,则对象可能引发此异常。例如,如果线程在其上迭代时直接修改集合如果集合具有fail fast迭代器,迭代器将引发此异常
在本例中,您在创建迭代器后修改了集合,因此遇到了异常