本文内容大多基于官方文档和网上前辈经验总结,经过个人实践加以整理积累,仅供参考。
1 fail-fast 机制
fail-fast 是 Java 集合类型的一种错误检测机制,在遍历集合期间,如果集合结构被修改,可能会抛出以下异常:java.util.ConcurrentModificationException
注意是可能,不是肯定!
2 fail-fast 触发的两类情景
(1) 单线程环境下,遍历集合过程中修改了集合的结构
(2) 多线程环境下,线程A在遍历集合X期间,线程B对集合X进行修改
注意,迭代器的 fail-fast 机制无法得到保证,fail-fast 迭代器会尽最大努力抛出 java.util.ConcurrentModificationException 异常。因此,迭代器的 fail-fast 机制应该仅用于检测 bug,编写的程序逻辑不应该依赖于 java.util.ConcurrentModificationException 异常。
3 fail-fast 检测原理
迭代器在遍历过程中是直接访问内部数据的,因此内部的数据在遍历的过程中无法被修改。为了保证不被修改,迭代器内部维护了一个标记 “mode” ,当集合结构改变(添加删除或者修改),标记”mode”会被修改,而迭代器每次的 hasNext() 和 next() 方法都会检查该”mode”是否被改变,当检测到被修改时,抛出 java.util.ConcurrentModificationException 异常。
与 fail-fast 机制对应的是 fail-safe 机制
4 fail-fast 示例
(1) 单线程:循环遍历 Map 同时向 Map 中添加新键值对
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.junit.Test;
public class FailFastTest {
@Test
public void test() {
Map<String, String> phones = new HashMap<>();
phones.put("Apple", "iPhone");
phones.put("Samsung", "Galaxy");
phones.put("Moto", "Z Play");
Iterator<String> iterator = phones.keySet().iterator();
while (iterator.hasNext()) {
System.out.println(phones.get(iterator.next()));
phones.put("Smartisan", "M1L");
}
}
}
运行测试结果:
(2) 多线程:线程 A 遍历 List 时,线程 B 从 List 末尾向前逐一移除
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class FailFastTest {
private static List<Integer> list = new ArrayList<>();
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
list.add(i);
}
new ThreadOne().start();
new ThreadTwo().start();
}
private static class ThreadOne extends Thread {
@Override
public void run() {
Iterator<Integer> iterator = list.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
private static class ThreadTwo extends Thread {
@Override
public void run() {
for (int i = 9; i >= 0; i--) {
list.remove(i);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
运行测试结果: