一、前言
在 Java 的集合结构中,如果我们同时进行遍历(for-each, iterator)和集合修改(add, set, remove…)操作时,就有可能发生异常。例如,线程 T1 在对集合进行遍历,而此时线程 T2 对集合进行添加元素;亦或者线程 T1 在对集合进行遍历的过程中,进行删除元素操作。
不同的集合在遇到上述这种情况时,会有不同的处理。按照处理的不同,划分为 Fail-Fast 和 Non-Fail-Fast(下文统称为 Fail-Safe)两类。前者不允许在迭代的过程中对集合进行增删操作,否则抛出 ConcurrentModificationException
异常;后者则允许这种操作,不会抛出异常。
注:本处的“对集合进行增删操作”指的是对集合自身的操作,而非借助 iterator 的操作。
二、Fail-Fast
Fail-Fast
类型的数据结构,在进行迭代时如果检测到集合对象发生了结构性修改会立即抛出 ConcurrentModificationException
,结构性修改指的是对该集合对象进行添加、删除或更新元素的操作。ArrayList
, HashMap
返回的迭代器就是典型的 Fail-Fast。
2.1 样例展示
import java.util.*;
public class FailFastExample {
public static void main(String[] args) {
Map<String, String> cityCode = new HashMap<>();
cityCode.put("Delhi", "India");
cityCode.put("Moscow", "Russia");
cityCode.put("New York", "USA"); // 此时 HashMap 对象的 modCount=3
// 返回 Iterator 对象时,会使用字段 expectedModCount 记录当前 HashMap 对象的 modCount
Iterator<String> iterator = cityCode.keySet().iterator();
while (iterator.hasNext()) {
// 每次调用 iterator.next() 时都会检查 expectedModCount 是否与 modCount 相等,若不等则抛出 ConcurrentModificationException
System.out.println(cityCode.get(iterator.next()));
// 往 Map 对象添加元素,迭代器在下一次调用 next() 时会抛出异常
cityCode.put