JavaSE---Fail-Fast
总结
主要用于集合类中,以确保 在遍历集合时如果集合本身被修改,则会立即抛出ConcurrentModificationException异常。
原理
- 内部计数器:每个集合对象都有一个内部计数器,称为
modCount(modification count)。每当集合结构被修改(比如添加或删除元素),这个计数器就会增加。 - 迭代器检查:当通过迭代器遍历集合时,迭代器会在每次调用
next()方法之前检查当前的modCount是否与创建迭代器时的expectedModCount相匹配。如果不匹配,说明集合已经被修改了,这时迭代器就会抛出ConcurrentModificationException。
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
transient Object[] elementData;
private int size;
// add
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e; // size ++
return true;
}
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++; // modCount++
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
// 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 void fastRemove(int index) {
modCount++; // 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 // --size
}
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 = 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 {
this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount) // modCount与expectedModCount比较
throw new ConcurrentModificationException();
}
}
}
示例
单线程
当使用iterator遍历List & 使用List的remove,将会ConcurrentModificationException;
List<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
list.add("Cherry");
list.add("Banana");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String fruit = iterator.next();
// 在遍历过程中修改集合
if ("Banana".equals(fruit)) {
list.remove(fruit);
}
}
System.out.println(list);
list的remove会修改modCount,导致modCount 与 expectedModCount不相等;
解决
1、使用iterator遍历时,使用iterator的remove,将不会修改modCount;
2、多线程环境,使用线程安全集合类;
3、同步控制,保证只有一个线程能访问集合;
浙公网安备 33010602011771号