当前位置:首页 > 开发 > 编程语言 > 编程 > 正文

ConcurrentModificationException原因分析

发表于: 2013-11-18   作者:bylijinnan   来源:转载   浏览次数:
摘要: package com.ljn.base; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * “对ArrayList进行遍历时,不要进行list.remove或者list.add操作” * 我只是记住了这条规则,但规则的背后,是什么原理? * 通过
package com.ljn.base;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 *  “对ArrayList进行遍历时,不要进行list.remove或者list.add操作”
 *  我只是记住了这条规则,但规则的背后,是什么原理?
 *  通过代码来说明(暂时不考虑多线程的情况):
 */
public class ConcurrentModificationExceptionTest {

    public static void main(String[] args) {
        remove(newArrayList(), "b");
        remove(newArrayList(), "a");
    }

    private static void remove(List<String> list, String itemToRemove) {
        Iterator<String> iterator = list.iterator();
        int i = 1;
        while (iterator.hasNext()) {
            String item = iterator.next();
            System.out.println(i++);
            if (item.equals(itemToRemove)) {
                list.remove(item);
                System.out.println(item + " is removed");
            } else {
                System.out.println(item);
            }
        }
        System.out.println();
    }
    
    private static List<String> newArrayList() {
        List<String> list = new ArrayList<String>();
        list.add("a");
        list.add("b");
        list.add("c");
        return list;
    }
    
    /*
很简单的程序,输出如下:
1
a
2
b is removed

1
a is removed
Exception in thread "main" java.util.ConcurrentModificationException
    at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
    at java.util.AbstractList$Itr.next(AbstractList.java:343)

为什么remove(newArrayList(), "a")会抛异常,而remove(newArrayList(), "b")就不会?

AbstractList里面有一个字段modCount,用来记录List“结构性改变”的次数,执行add或者remove都会使得modCount加1
AbstractList.iterator会创建一个AbstractList.Itr(内部类),而Itr备份了modCount,命名为expectedModCount
Itr执行next和remove操作前,都会调用checkForComodification方法检查expectedModCount是否等于modCount,如果不等,
就报ConcurrentModificationException
同时注意到Itr有一个指针cursor,表示下一个要遍历的元素的下标,初始值为0
Itr调用hasNext时,会将cursor与数组大小比较:
public boolean hasNext() {
            return cursor != size();
}

回到例子

先看remove(newArrayList(), "a"):
1.newArrayList()之后,modCount=3
2.list.iterator()之后,Itr的expectedModCount=modCount=3
3.调用hasNext(),next(),再调用list.remove(item),此时modCount=4
4.调用hasNext(),next(),在next里面进行检查,发现expectedModCount不等于modCount,于是报错

再看remove(newArrayList(), "b"):
1.newArrayList()之后,modCount=3, list.size=3
2.list.iterator()之后,Itr的expectedModCount=modCount=3,cursor=0
3.调用hasNext(),next(),打印a,list.size=2,cursor=1;没有对list做修改,因此expectedModCount=3
4.调用hasNext(),next(),检查expectedModCount和modCount,都等于3,因此检查通过,b is removed;
此时cursor=2,size=2
5.调用hasNext,此时cursor 与 size()都等于2,hasNext返回false,循环结束

由此可见,remove(newArrayList(), "b")只是侥幸地成功运行了,但仍然是错误的用法
*/
    
}

ConcurrentModificationException原因分析

  • 0

    开心

    开心

  • 0

    板砖

    板砖

  • 0

    感动

    感动

  • 0

    有用

    有用

  • 0

    疑问

    疑问

  • 0

    难过

    难过

  • 0

    无聊

    无聊

  • 0

    震惊

    震惊

编辑推荐
Java ConcurrentModificationException异常原因和解决方法   在前面一篇文章中提到,对Vector、Ar
Tomcat 假死原因分析报告 最近监控服务发现有台tomcat 的应用出现了无法访问的情况 ,由于已做了集
要:本文简要分析了无法重现的Bug的可能产生原因,包括环境不一致、缺少最准确的描述和浏览器的不当
1.OutOfMemoryError: Java heap space 堆溢出 原因:在JVM中如果98%的时间是用于GC且可用的 Heap s
首先,从处理流程上理解,它总是先使用最高效的原生方法来做处理 HTML文档一共有这么四个API: getE
有的时候,你在双击一个托管程序,或者使用Assembly.Load方法加载一些Assembly的时候,CLR会抛出Sys
测试环境:sql2005 + .NET2.0 同样的SQL语句,参数化查询和SQL语句直接执行的速度对比。数据库中存
由于业务需要,保存了一个图片链接地址到cookie中,js读取cookie显示图片,发现取出来的cookie值多
注:如果当你看到“临时”两字,就忽略过去的话,你很可能错过了更多。 已经有很多人抱怨苹果的10.8
工作之中写了个小的Web应用,类似于脚手架的demo应用,用spring搭的,在tomcat里运行。 程序写完了
版权所有 IT知识库 CopyRight © 2009-2015 IT知识库 IT610.com , All Rights Reserved. 京ICP备09083238号