在多线程的情况下是由Iterator遍历修改集合对象,报ConcurrentModificationException()异常的根因分析。

         在多线程下使用Iterator来迭代对象时,总会包ConcurrentModificationException();异常,经过我对list和Iterator相关源码的分析,终于搞明白了这个问题: 
         下面结合源代码来讨论这个问题:

          1、当我们调用一个List的iterator时,其实返回的并不是Itr对象(Iterator是一个接口),请看代码:
1  public Iterator<E> iterator() {
2    return new
 Itr();
3  }
       
       2、在Itr类中有这么一句话  int expectedModCount = modCount;首先讲一下这两个变量的含义:
             expectedModCount :创建当前的Itr对象时集合对象被修改的次数。他是Itr的变量。
             modCount:记录集合对象从创建到当前时间被做修改的次数。(集合每进行一次增删改查都会使modCount),他是Itr的外部类AbstractList
             的变量,且该变量在 AbstractList中被如此修饰protected transient int modCount = 0; 
            另外,Itr自己对集合对象进行了修改后,他会维持expectedModCount 和modCount的保持相等,请看以下代码
 1 //Itr的删除方法
 2 public void remove() {
 3         if (lastRet == -1
)
 4         throw new
 IllegalStateException();
 5 
            checkForComodification();
 6 

 7         try {
 8         AbstractList.this
.remove(lastRet);
 9         if (lastRet <
 cursor)
10             cursor--
;
11         lastRet = -1
;
12         expectedModCount =
 modCount;
13         } catch
(IndexOutOfBoundsException e) {
14         throw new
 ConcurrentModificationException();
15 
        }
16     }

            在代码的12行,Itr保证了expectedModCount 和modCount值的相等 ,modCount的值发生了改变吗,他改变了,带代码的第8行改变的,请看此处的代码:
         
 1public E remove(int index) {
 2
    RangeCheck(index);
 3

 4    modCount++
;
 5    E oldValue =
 elementData[index];
 6

 7    int numMoved = size - index - 1
;
 8    if (numMoved > 0
)
 9        System.arraycopy(elementData, index+1
, elementData, index,
10
                 numMoved);
11    elementData[--size] = null// Let gc do its work

12
13    return oldValue;
14    }

           在代码的第四行modCount发生了改变。 由此可以看出,在我们调用集合对象的iterator()方法的remove时总会使list的modCount的值自增1,但是Itr会自己维护该值和expectedModCount 的一致。
       3、试问:如果expectedModCount 和modCount的值如果不相等,会有什么问题呢,这就是报ConcurrentModificationException();异常的原因所在,请先看Itr的next()方法和next()调用的方法
 1//Itr的next方法:
 2public E next() {
 3
            checkForComodification();
 4        try 
{
 5        E next =
 get(cursor);
 6        lastRet = cursor++
;
 7        return
 next;
 8        }
 catch(IndexOutOfBoundsException e) {
 9
        checkForComodification();
10        throw new
 NoSuchElementException();
11        }

12    }

13
14//checkForComodification()方法:

15final void checkForComodification() {
16        if (modCount !=
 expectedModCount)
17        throw new
 ConcurrentModificationException();
18    }

19    }
20
    在next方法的一开始显示调用了checkForComodification()方法(见第三行),在checkForComodification()方法中做的工作就是比较expectedModCount 和modCount的值是否相等,如果不相等,就认为还有其他对象正在对当前的List进行操作,那个就会抛出ConcurrentModificationException异常。
       经过以上的分析,发现抛出ConcurrentModificationException异常处于调用next()方法时,比较expectedModCount 和modCount的值,如果两个值不相等,就会抛出异常,然而在什么情况下会使expectedModCount 和modCount的值不相等呢,只有在两个Itr同时对一个list进行操作的时候才会出现这样的问题,所以在以后的编码过程中在是由Iterator进行remove()时一定要考虑是否时多线程的,如果是请不要用Iterator进行remove(),而应该使用List的remove方法进行。

posted on 2008-04-01 09:56 linda 阅读(4381) 评论(3)  编辑  收藏

评论

# re: 在多线程的情况下是由Iterator遍历修改集合对象,报ConcurrentModificationException()异常的根因分析。 2009-03-27 23:02 梅友龙

好内容,这个说法我接受,谢了  回复  更多评论   

# re: 在多线程的情况下是由Iterator遍历修改集合对象,报ConcurrentModificationException()异常的根因分析。 2009-03-27 23:03 梅友龙

我比较喜欢研究技术的技术人,有时间可以聊聊~~  回复  更多评论   

# re: 在多线程的情况下是由Iterator遍历修改集合对象,报ConcurrentModificationException()异常的根因分析。[未登录] 2012-02-09 12:46 Jack

"如果是请不要用Iterator进行remove(),而应该使用List的remove方法进行。 "
说反了吧?  回复  更多评论   


只有注册用户登录后才能发表评论。


网站导航:
 

导航

<2009年3月>
22232425262728
1234567
891011121314
15161718192021
22232425262728
2930311234

统计

常用链接

留言簿(1)

随笔档案

搜索

最新评论

阅读排行榜

评论排行榜