fail-fast简介
fail-fast(快速失败),是Java集合的一种错误检测机制。当在遍历集合的过程中该集合在结构(改变集合大小)上发生变化时候,
有可能发生fail-fast,抛出java.util.ConcurrentModificationException异常。
fail-fast出现场景
- 单线程场景
-
public class FailFastSingleThreadTest { public static void main(String[] args) { List<String> lists = new ArrayList<>(10); for (int i = 0; i < 4; i++){ lists.add(String.valueOf(i)); } //fail-fast for (String list : lists) { lists.remove(3); } } } //output:Exception in thread "main" java.util.ConcurrentModificationException
-
- 多线程场景
-
public class FailFastMultiThread { private static List<String> lists = new ArrayList<>(10); static { for (int i = 0; i < 4; i++){ lists.add(String.valueOf(i)); } } public static void main(String[] args) { new Thread(new ForEachThread()).start(); new Thread(new EditThread()).start(); } //用于遍历 static class ForEachThread implements Runnable{ @Override public void run() { Iterator<String> iterator = lists.iterator(); while (iterator.hasNext()){ System.out.println(iterator.next()); try { Thread.sleep(100);//为了另外的线程加入,也是为了结合在遍历时候修改结构 } catch (InterruptedException e) { e.printStackTrace(); } } } } //用于修改结构 static class EditThread implements Runnable{ @Override public void run() { lists.add("8"); } } } //output:Exception in thread "Thread-0" java.util.ConcurrentModificationException
-
产生原因
集合能够遍历是因为迭代器的原因,而Iterator接口只是定义了具体的方法,集合需要实现该接口方法,
查看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;
@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是ArrayList的一个内部类,迭代器操作通过这个内部类,Itr有个expectedModCount属性,这个属性判断是否与modCount相等,如果不相等抛出异常,modCount记录list结构上发生变化的次数,可以看出在迭代时候checkForComodification()方法检测两个的值不相等就抛出异常
解决方法
- 单线程
- 使用迭代器的remove方法
public class NoFailFastSingleThread { public static void main(String[] args) { List<String> lists = new ArrayList<>(10); for (int i = 0; i < 4; i++){ lists.add(String.valueOf(i)); } Iterator<String> iterator = lists.iterator(); while (iterator.hasNext()){ String next = iterator.next(); if (next != null){ iterator.remove(); } } } }
- 多线程
- 使用java并发包下的类来代替对应的集合,如CopyOnWriteArrayList代替ArrayList,