代码块
Java
 
 
 
 
Exception in thread "main" java.util.ConcurrentModificationException
  at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
  at java.util.ArrayList$Itr.next(ArrayList.java:859)
  at com.mashibing.tank.Test2.main(Test2.java:14)
 

ArrayList在迭代删除元素时,如果使用不当会发生concurrentModification 异常,常见的错误使用场景

代码块
Java
 
 
 
 
Iterator<Integer> iterator = list.iterator();
while(iterator.hasNext()){
    Integer next = iterator.next();
        list.remove(next);
}
 
代码块
Java
 
 
 
 
for (Integer next:list
     ) {
    list.remove(next);
}
 

发生异常原因:

首先明确以上两种方式是等效的,原因:增强for在反编译后语句

代码块
Java
 
 
 
 
Iterator var4 = var1.iterator();
while(var4.hasNext()) {
    Integer var3 = (Integer)var4.next();
    var1.remove(var3);
}
 

然后我们去分析发生concurrentModification原因:

由于异常发生在 :java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909),我们先去看下此处代码

发现remove(intxOrObject) 方法为 ArrayList 内部类Itr的一个方法 ,当modCount != expectedModCount 时会抛出异常ConcurrentModificationException。

先来解释下概念:

modCount:为 成员变量 list 被修改的次数 ,每次add ,remove都会+1 (The number of times this list has been )

代码块
Java
 
 
 
 
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E>{
      //The number of times this list has been
      protected transient int modCount = 0;
 

expectedModCount:为listIterator 方法 局部变量,表示对ArrayList修改次数的期望值,它的初始值为modCount

代码块
Java
 
 
 
 
 
public Iterator<E> iterator() {
    return listIterator();
}
public ListIterator<E> listIterator(final int index) {
    checkForComodification();
    rangeCheckForAdd(index);
    final int offset = this.offset;
    return new ListIterator<E>() {
        int cursor = index;
        int lastRet = -1;
        //注意这里
        int expectedModCount = ArrayList.this.modCount;
        .......
        }
        ....
      }
      .....
  }
 
代码块
Java
 
 
 
 
 
private class Itr implements Iterator<E> {
    int cursor;       // index of next element to return
    int lastRet = -1; // index of last element returned; -1 if no such
    int expectedModCount = modCount;
    Itr() {}
    public boolean hasNext() {
        return cursor != size;
    }
    @SuppressWarnings("unchecked")
    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];
    }
}
 

这里假设原始list 长度为10(只做过新增,没有做过删除操作) 。

这时候最初 AbstractList.modCount =10 ;

Iterator.expectedModCount = modCount =10 ;

1.当第一次循环调用next时,无变动list ,所以expectedModCount = modCount =10 ,

2.当 arrayList.remove(indexOrObject)时,modCount++ 变为11 ,expectedModCount 依然为10 。

3.第二次调用next 时,Itr 会执行checkForComodification() ,也就是判断expectedModCount、 modCount 是否一致,如果不一致则抛出ConcurrentModificationException 。

正确姿势:

关注点:

1.增强for循环不要删除元素

2.使用Iterator<Integer> iterator = list.iterator(); 方式时,先获取元素,然后使用iterator.remove() 进行删除

代码块
Java
 
 
 
 
Iterator<Integer> iterator = list.iterator();
while (iterator.hasNext() ) {
    System.out.println(iterator.next());
    iterator.remove();
}
for (int i = 0; i < list.size(); i++) {
    System.out.println(list.get(i));
    list.remove(i);
}
 

为什么Iterator<Integer> iterator = list.iterator(); 方式时 用iterator remove 不会出现问题?看源码:

代码块
Java
 
 
 
 
private class Itr implements Iterator<E> {
    public void remove() {
    if (lastRet < 0)
        throw new IllegalStateException();
    checkForComodification();
    try {
        ArrayList.this.remove(lastRet);
        cursor = lastRet;
        lastRet = -1;
        //关注这里, Itr里将modCount 赋值给expectedModCount 
        expectedModCount = modCount;
    } catch (IndexOutOfBoundsException ex) {
        throw new ConcurrentModificationException();
    }
    }
 

为什么普通循环不会有ConcurrentModificationException ,看源码:

代码块
Java
 
 
 
 
public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
    public boolean remove(Object o) {
        if (o == null) {
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }
    private void fastRemove(int index) {
        modCount++;
        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // clear to let GC do its work
    }
}
 

最新文章

  1. oracle数据库表空间追加数据库文件方法
  2. BFC与CFC
  3. display:block 不起作用
  4. Java中的泛型
  5. 评价软件_搜狗输入法(pc端)
  6. hdu4123-Bob’s Race(树形dp+rmq+尺取)
  7. Android 解析内存泄漏
  8. 浙江工商大学15年校赛C题 我删我删,删删删 【简单模拟】
  9. 2015: [Usaco2010 Feb]Chocolate Giving
  10. Git Flow Note
  11. WINCE之“系统事件”——System/Events
  12. .net prams关键字
  13. 2018-2019-2 网络对抗技术 20162329 Exp5 MSF基础应用
  14. WebApi集成Swagger
  15. Kafka集群管理工具kafka-manager的安装使用
  16. java线程池和中断总结
  17. LeetCode 104 Maximum Depth of Binary Tree 解题报告
  18. jfinal 项目 控制层、ORM层、AOP层,在发表之前一定要记得保存
  19. Java生成xlsx格式的excel文件
  20. windows上安装db2 spatial extender和ArcSDE的问题

热门文章

  1. SpringMVC源码剖析1——执行流程
  2. eclipse 大括号改为C语言一样的代码块
  3. Java IO: 字节和字符数组
  4. jenkins邮件内容模板
  5. 关于(Building tool)的认识以及当下流行的Building tool有哪些?
  6. HashMap底层分析
  7. Jmeter之Beanshell---使用Java处理JSON块
  8. 抛开贾跃亭!法拉第FF91能成功吗?
  9. 测试工程师不懂AI,还有未来吗?
  10. rsync auth failed on module xxx