目录
快速失败——fail-fast
异常原因
正常原因
安全失败“fail-safe”
快速失败——fail-fast
java的快速失败机制是java集合框架中的一种错误检测机制,当多个线程对集合中的内容进行修改时可能就会抛出ConcurrentModificationException异常。不仅仅在多线程状态下,在单线程中使用增强for循环一边遍历集合一边修改集合的元素也会抛出ConcurrentModificationException异常。例如:
public class Main {public static void main(String[] args) {List<String> list = new ArrayList<>();list.add("java");list.add("python");list.add("c++");for (String s:list){list.remove(s);}}
}
抛出异常:
正确做法使用迭代器的remove()方法,可正常删除
public static void main(String[] args) {List<String> list = new ArrayList<>();list.add("java");list.add("python");list.add("c++");Iterator<String> iterator = list.iterator();while (iterator.hasNext()){iterator.next();//获取下一个元素iterator.remove();//删除当前元素}}
异常原因
首先查看list.remove()源码:
根据值找到对应的索引后调用fastRemove(index)方法 ,查看fastRemove(int index)方法
发现第一个元素可以正常删除,但由于使用for-each循环,底层实际使用的是迭代器遍历当执行for (String s : list)时,Java会隐式地创建一个迭代器,并调用iterator()方法开始迭代。迭代过程:在每次循环中,Java会调用迭代器的next()方法获取下一个元素,并将其赋值给s。删除元素:然后执行list.remove(s),这实际上调用了remove()方法,删除了当前引用的元素。
在调用next()时,里面包含checkForComodification();方法,该方法将modCount和expectedModCount进行比较。
checkForComodification()源码:
final void checkForComodification() {if (modCount != expectedModCount)throw new ConcurrentModificationException();}
因此抛出了 ConcurrentModificationException异常。
正常原因
由于迭代器使用的remove()和上面的remove()方法不同,源码:
迭代器的remove()方法保证了expectedModCount = modCount;因此也保证了不会出现ConcurrentModificationException异常。
虽然在线程下,使用迭代器可以避免ConcurrentModificationException异常,但是在多线程下,使用迭代器的remove()方法还会报异常。
这是因为modCount是在AbstractList类中定义的,而expectedModCount是在ArrayList内部类中定义,所以modCount是一个共享变量,而expectedModCount是属于线程各自的。
例如:当线程1更新了modCount属于自己的expectedModCount,而线程2只有看到modCount更新,自己的expectedModCount并没有更新,因此抛出ConcurrentModificationException异常。
例如:
ArrayList
Vector
HashMap
HashSet
LinkedHashMap
LinkedHashSet
实现了"fail-fast"机制。
安全失败“fail-safe”
在遍历集合时,不是直接在集合内容上进行访问,而是先复制原有集合内容,在复制的集合上进行遍历,在遍历时,对集合的修改是不会被迭代器检测到,所以不会抛出ConcurrentModificationException异常。
缺点:迭代器遍历的是开始遍历那一刻拿到的集合拷贝,在遍历期间,原集合发生了修改,迭代器是无法访问到的。
在java.util.concurrent包下的容器都是安全失败,可以在多线程下并发使用:
例如:
CopyOnWriteArrayList、
CopyOnWriteArraySet
,ConcurrentHashMap
等