集合操作的ConcurrentModificationException异常分析,为什么有时候循环remove不会异常?Iterator方式也会异常吗?
2016-10-11 14:52
731 查看
在我们代码中,禁止在foreach遍历list的时候直接使用list.remove()方法来删除元素的,会ConcurrentModificationException。不同的集合使用不同的方式,ArrayList,Vector,CopyOnWriteArrayList*
**单线程情况:如果实际应用场景下有在遍历时删除元素的需求,如果容器为ArrayList或者Vector请使用Iterator中的remove()方法;若果是CopyOnWriteArrayList 可以直接使用for循环remove,注意CopyOnWriteArrayList
使用Iterator的remove反而会报错。追根溯源大家看源码吧。**1.先看一下面代码?会产生ConcurrentModificationException?```public
static void main(String[] args) { List<String> list = new ArrayList<String>(); list.add("a");
list.add("b"); list.add("c"); for (String s : list) { if ("b".equals(s))
{ list.remove(s); } }
System.out.println(list);}```2.会产生ConcurrentModificationException?```public
static void main(String[] args) { List<String> list = new CopyOnWriteArrayList<String>(); list.add("a");
list.add("b"); list.add("c"); for (String s : list) { if ("b".equals(s))
{ list.remove(s); } }
System.out.println(list);}```3.会产生ConcurrentModificationException?```public
static void main(String[] args) { List<String> list = new Vector<String>(); list.add("a");
list.add("b"); list.add("c"); for (String s : list) { if ("b".equals(s))
{ list.remove(s); } }
System.out.println(list);}```实际的结果是,程序运行完成,输出[a,
c],因为删除的是倒数第二个元素。如果杀出的不是倒数第二个元素,只有第二段代码是正常运行的。下面看一下ArrayList的遍历:```
private class Itr implements Iterator<E> { int cursor; // index of next element to return int lastRet = -1; // index of last element returned;
-1 if no such int expectedModCount = modCount; public boolean hasNext() {
return cursor != size; } @SuppressWarnings("unchecked")
public E next() { checkForComodification(); int i = cursor; if (i >= size)
throw new NoSuchElementException(); Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length)
throw new ConcurrentModificationException(); cursor = i + 1; return (E) elementData[lastRet = i];
} public void remove() { if (lastRet < 0)
throw new IllegalStateException(); checkForComodification(); try {
ArrayList.this.remove(lastRet); cursor = lastRet; lastRet = -1; expectedModCount
= modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException();
} } final void checkForComodification() {
if (modCount != expectedModCount) throw new ConcurrentModificationException(); }
}```遍历时每当Itr去获取下一个元素时,就会调用checkForComodification()去检查ArrayList是否被修过,如果被修改过就会抛出ConcurrentModificationException,调用ArrayList中的remove方法时,modCount被加1,所以会造成modCount的值与expectedModCount不相等。所以当Itr尝试去获取下一个元素时,一定会抛ConcurrentModificationException。看remove的源码:```
public boolean remove(Object o) { if (o == null) { for (int index = 0; index < size; index++)
if (elementData[index] == null) { fastRemove(index); return true; }
} else { for (int index = 0; index < size; index++) if (o.equals(elementData[index])) {
fastRemove(index); return true; } }
return false; } /*
* Private remove method that skips bounds checking and does not * return the value removed. */
private void fastRemove(int index) { modCount++; int numMoved = size - index - 1;
if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved);
elementData[--size] = null; // clear to let GC do its work }```**那么又是为什么程序在删除"b"元素之后没有抛这个异常呢?----------------------------**```public
boolean hasNext() { return cursor != size();}```**这个方法,
当元素"b"被删除后,cursor的值正好与数组的size()相等,所以Itr的遍历任务已经结束,不再会去获取下一个元素,所以也就没有抛异常了。****当然这个情况只有在删除数组中的倒数第二个元素时才会出现,只是一个巧合现象,在我们代码规范中,还是绝对禁止在遍历list的时候直接使用list.remove()方法来删除元素的。**#总结:*
**如果实际应用场景下有在遍历时删除元素的需求,如果容器为ArrayList或者Vector请使用Iterator中的remove()方法;若果是CopyOnWriteArrayList
可以直接使用for循环remove,注意CopyOnWriteArrayList 使用Iterator的remove反而会报错。追根溯源大家看源码吧。更好的方式是不要直接修改原来的集合类容器,取出需要的元素丢到新的容器返回给需要使用的场景------------------------------------------------------------------------
**单线程情况:如果实际应用场景下有在遍历时删除元素的需求,如果容器为ArrayList或者Vector请使用Iterator中的remove()方法;若果是CopyOnWriteArrayList 可以直接使用for循环remove,注意CopyOnWriteArrayList
使用Iterator的remove反而会报错。追根溯源大家看源码吧。**1.先看一下面代码?会产生ConcurrentModificationException?```public
static void main(String[] args) { List<String> list = new ArrayList<String>(); list.add("a");
list.add("b"); list.add("c"); for (String s : list) { if ("b".equals(s))
{ list.remove(s); } }
System.out.println(list);}```2.会产生ConcurrentModificationException?```public
static void main(String[] args) { List<String> list = new CopyOnWriteArrayList<String>(); list.add("a");
list.add("b"); list.add("c"); for (String s : list) { if ("b".equals(s))
{ list.remove(s); } }
System.out.println(list);}```3.会产生ConcurrentModificationException?```public
static void main(String[] args) { List<String> list = new Vector<String>(); list.add("a");
list.add("b"); list.add("c"); for (String s : list) { if ("b".equals(s))
{ list.remove(s); } }
System.out.println(list);}```实际的结果是,程序运行完成,输出[a,
c],因为删除的是倒数第二个元素。如果杀出的不是倒数第二个元素,只有第二段代码是正常运行的。下面看一下ArrayList的遍历:```
private class Itr implements Iterator<E> { int cursor; // index of next element to return int lastRet = -1; // index of last element returned;
-1 if no such int expectedModCount = modCount; public boolean hasNext() {
return cursor != size; } @SuppressWarnings("unchecked")
public E next() { checkForComodification(); int i = cursor; if (i >= size)
throw new NoSuchElementException(); Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length)
throw new ConcurrentModificationException(); cursor = i + 1; return (E) elementData[lastRet = i];
} public void remove() { if (lastRet < 0)
throw new IllegalStateException(); checkForComodification(); try {
ArrayList.this.remove(lastRet); cursor = lastRet; lastRet = -1; expectedModCount
= modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException();
} } final void checkForComodification() {
if (modCount != expectedModCount) throw new ConcurrentModificationException(); }
}```遍历时每当Itr去获取下一个元素时,就会调用checkForComodification()去检查ArrayList是否被修过,如果被修改过就会抛出ConcurrentModificationException,调用ArrayList中的remove方法时,modCount被加1,所以会造成modCount的值与expectedModCount不相等。所以当Itr尝试去获取下一个元素时,一定会抛ConcurrentModificationException。看remove的源码:```
public boolean remove(Object o) { if (o == null) { for (int index = 0; index < size; index++)
if (elementData[index] == null) { fastRemove(index); return true; }
} else { for (int index = 0; index < size; index++) if (o.equals(elementData[index])) {
fastRemove(index); return true; } }
return false; } /*
* Private remove method that skips bounds checking and does not * return the value removed. */
private void fastRemove(int index) { modCount++; int numMoved = size - index - 1;
if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved);
elementData[--size] = null; // clear to let GC do its work }```**那么又是为什么程序在删除"b"元素之后没有抛这个异常呢?----------------------------**```public
boolean hasNext() { return cursor != size();}```**这个方法,
当元素"b"被删除后,cursor的值正好与数组的size()相等,所以Itr的遍历任务已经结束,不再会去获取下一个元素,所以也就没有抛异常了。****当然这个情况只有在删除数组中的倒数第二个元素时才会出现,只是一个巧合现象,在我们代码规范中,还是绝对禁止在遍历list的时候直接使用list.remove()方法来删除元素的。**#总结:*
**如果实际应用场景下有在遍历时删除元素的需求,如果容器为ArrayList或者Vector请使用Iterator中的remove()方法;若果是CopyOnWriteArrayList
可以直接使用for循环remove,注意CopyOnWriteArrayList 使用Iterator的remove反而会报错。追根溯源大家看源码吧。更好的方式是不要直接修改原来的集合类容器,取出需要的元素丢到新的容器返回给需要使用的场景------------------------------------------------------------------------
相关文章推荐
- 在多线程的情况下是由Iterator遍历修改集合对象,报ConcurrentModificationException()异常的根因分析
- 关于对Map、List等集合操作抛出ConcurrentModificationException 异常问题
- Java集合之ConcurrentModificationException(并发修改异常)分析
- java.util.ConcurrentModificationException 集合remove异常
- 循环List删除元素抛ConcurrentModificationException异常原因分析
- 深入分析集合并发修改异常(源码分析)java.util.ConcurrentModificationException
- Java集合迭代器之fail-fast机制: 关于java集合的遍历以及ConcurrentModificationException(并发操作异常)
- 关于java集合的遍历以及ConcurrentModificationException(并发操作异常)
- 集合操作出现的ConcurrentModificationException(源码分析)
- 关于Map表循环过程删除操作出现的java.util.ConcurrentModificationException 异常
- LinkedBlockingQueue操作,线程安全问题,ConcurrentModificationException 异常分析与解决方案
- 集合遍历时删除元素异常(ConcurrentModificationException)分析
- ConcurrentModificationException 集合并发修改异常 解决
- ConcurrentModificationException遍历集合时,不能对集合进行修改操作
- 为什么会出现 java.util.ConcurrentModificationException 异常?
- 主题:为什么会出现 java.util.ConcurrentModificationException 异常?
- 修改List报ConcurrentModificationException异常原因分析
- 为什么会出现 java.util.ConcurrentModificationException 异常?
- ConcurrentModificationException 的异常分析
- JCIP_5_01_CopyOnWriteArrayList为什么不会产生ConcurrentModificationException?