原文:https://blog.csdn.net/lululove19870526/article/details/70808903
java list中删除元素用remove()报错的fail-fast机制原理以及解决方案
现在有一个list,有6个元素,值分别是1、5、5、8、5、10,现需要删除值为5的元素
第一种
import java.util.ArrayList;
import java.util.List;
public class ListRemove1 {
public static void main(String args[]) {
List
list.add(1);
list.add(5);
list.add(5);
list.add(8);
list.add(5);
list.add(10);
for (int j = 0; j < list.size(); j++) {
if (list.get(j) == 5) {
list.remove(j);
}
}
outputList(list);
}
private static void outputList(List
for (int i = 0; i < list.size(); i++) {
System.out.print(list.get(i)+" ");
}
}
}
运行结果
1 5 8 10
这结果显然不是我们的预期,我们是希望删除List中所有为5的元素,但输出结果中却出现了5,这是因为在i等于1时,删除了List中的index为1的元素5,这时候list为[1,5,8,5,10], 但接下来,i递增后,等于2,在list.get(i)时,取出来的结果就成为了8了,也就是说随着list元素的删除,index是随之变化的,这就是其中的陷阱
第二种
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ListRemove2 {
public static void main(String args[]) {
List
list.add(1);
list.add(5);
list.add(5);
list.add(8);
list.add(5);
list.add(10);
/*
for (int i1 : list) {
if (i1 == 5) {
list.remove(i1);
}
}
*/
Iterator
while(iterator.hasNext()){
if(iterator.next() == 5){
list.remove(5);
}
}
outputList(list);
}
private static void outputList(List
for (int i = 0; i < list.size(); i++) {
System.out.print(list.get(i)+" ");
}
}
}
上面代码不管用增强for循环还是用Iterator遍历list,用list.remove()方法都报下面的错误:
之所以报上面的错误是因为发生了fail-fast 事件。
fail-fast 机制是java集合(Collection)中的一种错误机制。当多个线程对同一个集合的内容进行操作时,就可能会产生fail-fast事件。
例如:当某一个线程A通过iterator去遍历某集合的过程中,若该集合的内容被其他线程所改变了;那么线程A访问集合时,就会抛出ConcurrentModificationException异常,产生fail-fast事件。
1.报ConcurrentModificationException异常的原因
ConcurrentModificationException是在操作Iterator时抛出的异常,ArrayList的Iterator是在父类AbstractList.java中实现的,具体源码:
public abstract class AbstractList
public Iterator
return new Itr();
}
private class Itr implements Iterator
/**
* Index of element to be returned by subsequent call to next.
*/
int cursor = 0;
/**
* Index of element returned by most recent call to next or
* previous. Reset to -1 if this element is deleted by a call
* to remove.
*/
int lastRet = -1;
/**
* The modCount value that the iterator believes that the backing
* List should have. If this expectation is violated, the iterator
* has detected concurrent modification.
*/
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size();
}
public E next() {
checkForComodification();
try {
E next = get(cursor);
lastRet = cursor++;
return next;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
public void remove() {
if (lastRet == -1)
throw new IllegalStateException();
checkForComodification();
try {
AbstractList.this.remove(lastRet);
if (lastRet < cursor)
cursor--;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
protected transient int modCount = 0;
}
ArrayList中的remove()的实现
public class ArrayList
RandomAccess, Cloneable, java.io.Serializable {
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; // Let gc do its work
}
}
无论是add()、remove(),还是clear(),只要涉及到修改集合中的元素个数时,都会改变modCount的值
从源码中我们可以看出:
1) Iterator
2)遍历到第二个元素即值为5的时候,list.remove(5);从ArrayList中的remove()实现中发现:modCount++;此时modCount的值为7
3)在执行if(iterator.next() == 5)这语句即调用iterator的next()方法时,next()方法实现会调用checkForComodification();,该方法会执行 if (modCount != expectedModCount),即比较modCount和expectedModCount的值是否相等,此时expectedModCount的值为6而modCount的值为7,这两个值不相等,所以抛出
throw new ConcurrentModificationException();这个异常
第三种即解决方案:调用iterator的iterator.remove()方法,该方法的实现中,会执行expectedModCount = modCount;这个语句,即expectedModCount赋值为modCount;
这样就保证expectedModCount 等于modCount,不会抛出ConcurrentModificationException()这个异常
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ListRemove4 {
public static void main(String args[]) {
List
list.add(1);
list.add(5);
list.add(5);
list.add(8);
list.add(5);
list.add(10);
Iterator
while(iterator.hasNext()){
if(iterator.next() == 5){
iterator.remove();
}
}
outputList(list);
}
private static void outputList(List
for (int i = 0; i < list.size(); i++) {
System.out.print(list.get(i)+" ");
}
}
}
运行结果:
1 8 10
---------------------