黑马程序员技术交流社区

标题: 访问ArrayList集合元素而抛出异常的联想 [打印本页]

作者: 吴扬    时间: 2012-7-6 12:02
标题: 访问ArrayList集合元素而抛出异常的联想
毕老师在讲ListIterator这部分内容的时候,先是引出了一个异常,那就是ConcurrentModificationException异常,是因为对ArrayList集合中的元素即调用了List中的方法又调用了Iterator中的方法进行访问,这样才会抛出该异常。本人就觉得这种情况很像多线程中的并发访问异常,这个异常可以用解决多线程的同步锁的思想去解决吗?多线程可不可以用于解决非多线程而产生的异常呢?
作者: 杨_扬    时间: 2012-7-6 12:36
本帖最后由 杨_扬 于 2012-7-6 13:00 编辑

问的不错
首先,这的确是类似并发访问
老师用的啥例子我不知道,那部分视频我没看,我给出一个例子
ArrayList<String> list=new ArrayList<String>();
list.add("aa");
list.add("bb");
list.add("cc");
for(String s:list){
       System.out.println(m);
       list.add("dd");//look here ,problem point
}
你肯定知道,这段代码一执行,立马就跳ConcurrentModificationException了是吧?
用你说的同步锁的思想,解释一下
首先,有两个操作,一个是iterator在遍历集合,另一个操作是list在添加元素,我们将这两个操作视为两个线程。
这里,已经满足了线程同步的基本要素
1. 有两个或以上线程
2. 操作同一个资源(就是那个ArrayList)
假设,我们将List中的所有操作都包括在同步块中,那么当iterator拿到了执行权,只要遍历不结束,list就没办法add,反之亦然
这个同步锁的锁是谁呢?就是list.this对吧

那么,对于ArrayList来说,“锁”是谁呢?这就还要去看他的父类
AbstractList的源代码了。
AbstractList包含一个 modCount(modify count 修改次数)变量,它的初始值是0,当集合每被修改一次时(调用add,remove等方法),modCount加1。因此,modCount如果不 变,表示集合内容未被修改。
另外,还有一个叫
expectedModCount(expected modify count 预期修改次数)的变量
Itr是List用来实现Iteratorj接口的内部类,返回Iterator接口的实例,初始化时用expectedModCount记录集合的modCount变量,此后它会检测modCount的值
如果modCount与一开始记录在expectedModeCount中的值不等,说明集合内容被修改过,此时会抛出ConcurrentModificationException。
此时,
expectedModCount就相当于List集合的“锁”我们再回过头来分析一下程序
list.add("aa");
list.add("bb");
list.add("cc");
这三步执行完,对list做了三次修改,因此
modCount的值为3,而expectedModeCount的值也为3,接下来开始进入循环for(String s:list){
       System.out.println(m);
       list.add("dd");//look here ,problem point
}
当执行到add操作的时候
modCount的值变为了4,但是expectedModeCount的值依然为3
在进入下一次迭代之前,iterator比较这两个值,发现不等,抛异常。基本原理就是这样。


作者: 吴扬    时间: 2012-7-6 21:33
杨_扬 发表于 2012-7-6 12:36
问的不错
首先,这的确是类似并发访问
老师用的啥例子我不知道,那部分视频我没看,我给出一个例子

你这里用for循环进行遍历,而不是用迭代器进行遍历,这样就不会造成并发访问异常呀!




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2