ConcurrentModificationException原因分析_JAVA_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > JAVA > ConcurrentModificationException原因分析

ConcurrentModificationException原因分析

 2013/11/18 21:20:44  bylijinnan  程序员俱乐部  我要评论(0)
  • 摘要:packagecom.ljn.base;importjava.util.ArrayList;importjava.util.Iterator;importjava.util.List;/***“对ArrayList进行遍历时,不要进行list.remove或者list.add操作”*我只是记住了这条规则,但规则的背后,是什么原理?*通过代码来说明:*/publicclassConcurrentModificationExceptionTest{publicstaticvoidmain
  • 标签:原因 分析
class="java">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")只是侥幸地成功运行了,但仍然是错误的用法
*/
    
}
上一篇: CopyOnWriteArrayList vs ArrayList 下一篇: 没有下一篇了!
发表评论
用户名: 匿名