ConcurrentModificationException原因分析
编程技术  /  houtizong 发布于 3年前   82
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; } /*很简单的程序,输出如下:1a2b is removed1a is removedException 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加1AbstractList.iterator会创建一个AbstractList.Itr(内部类),而Itr备份了modCount,命名为expectedModCountItr执行next和remove操作前,都会调用checkForComodification方法检查expectedModCount是否等于modCount,如果不等,就报ConcurrentModificationException同时注意到Itr有一个指针cursor,表示下一个要遍历的元素的下标,初始值为0Itr调用hasNext时,会将cursor与数组大小比较:public boolean hasNext() { return cursor != size();}回到例子先看remove(newArrayList(), "a"):1.newArrayList()之后,modCount=32.list.iterator()之后,Itr的expectedModCount=modCount=33.调用hasNext(),next(),再调用list.remove(item),此时modCount=44.调用hasNext(),next(),在next里面进行检查,发现expectedModCount不等于modCount,于是报错再看remove(newArrayList(), "b"):1.newArrayList()之后,modCount=3, list.size=32.list.iterator()之后,Itr的expectedModCount=modCount=3,cursor=03.调用hasNext(),next(),打印a,list.size=2,cursor=1;没有对list做修改,因此expectedModCount=34.调用hasNext(),next(),检查expectedModCount和modCount,都等于3,因此检查通过,b is removed;此时cursor=2,size=25.调用hasNext,此时cursor 与 size()都等于2,hasNext返回false,循环结束由此可见,remove(newArrayList(), "b")只是侥幸地成功运行了,但仍然是错误的用法*/ }
请勿发布不友善或者负能量的内容。与人为善,比聪明更重要!
技术博客集 - 网站简介:
前后端技术:
后端基于Hyperf2.1框架开发,前端使用Bootstrap可视化布局系统生成
网站主要作用:
1.编程技术分享及讨论交流,内置聊天系统;
2.测试交流框架问题,比如:Hyperf、Laravel、TP、beego;
3.本站数据是基于大数据采集等爬虫技术为基础助力分享知识,如有侵权请发邮件到站长邮箱,站长会尽快处理;
4.站长邮箱:[email protected];
文章归档
文章标签
友情链接