list操作中的 ConcurrentModificationException 快速失败
1.错误出现
foreach循环其实就是根据list对象创建一个iterator迭代对象,用这个迭代对象来遍历list,相当于list对象中元素的遍历托管给了iterator,如果要对list进行增删操作,都必须经过iterator。
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];
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
当使用for循环遍历list的时候,根据上面的代码可以知道,一开始的时候保存了一个expectedModCount这个的初始值为初始的modCount,如果在遍历过程中出现了修改list的长度,就会出现modCount值的改变(非迭代器删除方法),则在下一次的遍历过程中就会出现两个值的不相等,就会抛出ConcurrentModificationException错误
2.解决办法
使用迭代器迭代list
Iterator it = list.iterator();
while (it.hasNext()) {
if (it.next().equals("3")) {
it.remove();
}
}
简单来讲就是迭代器接管了迭代修改等一系列事情,如此一来,迭代器的修改方法也会去关注expectedModCount值的变化,这样就不会出现两个的值不一样的问题
附上两个不同的删除方法:
//list里面自带的删除方法
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;
}
//上述方法并没有对expectedModCount进行修改
//迭代器附带的删除方法
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount; // 处理expectedModCount
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
//对expectedModCount进行了修改
3.多线程问题
多线程情况下,就会出现当迭代器remove被多次不同线程调用的情况,这样还是会出现错误
解决方法:对迭代器加锁,或者使用安全错误的copyonwritearraylist