测试代码为:
html
public static void main(String[] args) { List<String> strList = new ArrayList<String>(); strList.add("1"); strList.add("2"); strList.add("3"); strList.add("4"); for(String str:strList){ if(str.equals("4")){ strList.remove(str); } } }
运行后结果以下:
java
跟踪代码,抛出异常的地方具体在:函数
public E next() { checkForComodification(); try { E next = get(cursor); lastRet = cursor++; return next; } catch (IndexOutOfBoundsException e) { checkForComodification(); throw new NoSuchElementException(); } }
遍历时返回一个元素以前,会调用checkForComodification()函数进行检查,该函数实现为:测试
final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); }
modCount 为ArrayList修改的次数,expectedModCount 为指望修改的次数,在删除第四个元素以前,modCount 和expectedModCount 均为4(4次add),而调用ArrayList的remove()方法后,modCount 变为5,但该方法未修改expectedModCount ,其值仍为4,所以出现上述异常。spa
解决方法为:单线程环境中,使用 Iterator的remove()方法取代ArrayList的remove()方法,能够避免ConcurrentModificationException异常。线程
巧合的是,若是要删除的元素正好是集合中倒数第二个元素,则不会抛出此异常。Iterator遍历获取一个元素以前会先调用hasNext()方法来判断是否还有元素,该方法实现为:code
public boolean hasNext() { return cursor != size(); }
其中cursor为遍历的位置,从0开始,在上面的next()方法中被更新。htm
删除倒数第二个元素"3"后,已经访问了3个元素,cursor指向下一个应该访问的元素位置,即3,而size()也返回3,hasNext()返回false,就不会调用next()方法,所以也不存在ConcurrentModificationException异常。blog
删除元素"4"后,cursor的值变为4,而size()返回3,hasNext()返回true,所以调用next()方法时就会抛出ConcurrentModificationException异常。rem
附上一篇资料:
Java ConcurrentModificationException异常缘由和解决方法: