情况一、使用迭代器Iterator循环时,对集合增加、删除,抛出并发修改 异常
代码:
public class LinkedListTest {
// 并发修改异常
public static void main(String[] args) {
ArrayList<String> aList=new ArrayList<String>();
//向集合中添加元素
aList.add("a");
aList.add("b");
aList.add("c");
aList.add("d");
System.out.println("移除前:"+aList);
//创建迭代器
Iterator<String> it=aList.iterator();
while(it.hasNext())
{
if("b".equals(it.next()))
{
aList.remove("b");//移除指定元素
}
}
System.out.println("移除后:"+aList);
}
}
控制台输出:
移除前:[a, b, c, d]
Exception in thread "main" java.util.ConcurrentModificationException //并发修改异常
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
at java.util.ArrayList$Itr.next(ArrayList.java:851)
at collection.LinkedHashSetTest.main(LinkedHashSetTest.java:52)
分析:
(1)哪里抛出的异常?
上述代码 ,迭代器对象it.next()方法抛出的
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException(); //这里抛出的异常
cursor = i + 1;
return (E) elementData[lastRet = i];
}
(2) 出现的原因:
鼠标放在 iterator()方法上,Ctrl+鼠标左键,看到源码
参数说明:
cursor:表示下一个元素的索引位置
lastRet:表示上一个元素的索引位置
expectModCount:预期被修改的次数
在集合内部维护一个字段modCount用于记录集合被修改的次数,每当集合内部结构发生变化(add,remove,set)时,modCount+1。
在迭代器内部也维护一个字段expectedModCount,同样记录当前集合修改的次数,初始化为集合的modCount值。当我们在调用Iterator进行遍历操作时,如果有其他线程修改list会出现modCount!=expectedModCount的情况,就会报并发修改异常java.util.ConcurrentModificationException
解释:
一开始的创建集合,每次往集合中添加元素,那么集合内部就会 modCount+1。同理迭代器内部的维护字段expectedModCount记录当前修改的次数。
问题来了。代码执行了 aList.remove("b");之后 modCount+1,再次进入循环。调用迭代器的next()方法
next()源码:
public E next() {
checkForComodification();//检查集合的modCount 与迭代器expectedModCount
int i = cursor;
if (i >= SubList.this.size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (offset + i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[offset + (lastRet = i)];
}
checkForComodification()源码:
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
执行发现 modCount != expectedModCount 记录次数不一致,搞事情!
解决方案:
使用 ListIterator<String> it = aList.listIterator();
public class LinkedListTest {
// 并发修改异常
public static void main(String[] args) {
ArrayList<String> aList=new ArrayList<String>();
//向集合中添加元素
aList.add("a");
aList.add("b");
aList.add("c");
aList.add("d");
System.out.println("移除前:"+aList);
//创建迭代器
// Iterator<String> it=aList.iterator();
ListIterator<String> it = aList.listIterator();
while(it.hasNext())
{
if("b".equals(it.next()))
{
//aList.remove("b");//移除指定元素
it.remove();
}
}
System.out.println("移除后:"+aList);
}
}
情况一到此结束。
情况二、增强for循环,不能删除、增加 可以set 、输出
代码:
ArrayList<String> aList=new ArrayList<String>();
//向集合中添加元素
aList.add("a");
aList.add("b");
aList.add("c");
aList.add("d");
System.out.println("移除前:"+aList);
//增强for循环,不能删除、增加 可以set 、输出
for (String string : aList) {
if("b".equals(string))
// aList.remove("b");//异常
// aList.add("f") ;//异常
aList.set(1,"v");//正常
}