Java 集合遍历过程中修改数据触发 Fail-Fast 机制 ,导致报ConcurrentModificationException异常

Java Fail-Fast 机制

Fail-Fast 机制是 Java 集合框架中的一种错误检测机制,用于在遍历集合时检测结构修改。如果在迭代器创建之后,集合被修改(例如添加或删除元素),并且这种修改不是通过迭代器自身的 remove() 方法进行的,那么迭代器会立即抛出 ConcurrentModificationException 异常,以防止不一致或不可预测的行为。

工作原理
  1. 修改计数器

    • 集合类(如 ArrayListHashMap 等)内部维护一个 modCount 计数器,记录集合被结构性修改的次数(结构性修改包括添加或删除元素,但不包括通过迭代器自身的 remove() 方法进行的删除)。
  2. 迭代器的预期修改计数

    • 当创建迭代器时,迭代器会记录当前集合的 modCount 值,作为其 expectedModCount
    • 在每次调用迭代器的 next() 方法时,迭代器会检查 expectedModCount 是否与集合的当前 modCount 一致。
  3. 检测不一致

    • 如果在迭代过程中,集合的 modCount 发生变化(即 expectedModCount 不等于 modCount),迭代器会立即抛出 ConcurrentModificationException 异常。
示例代码
java 复制代码
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class FailFastExample {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("A");
        list.add("B");
        list.add("C");

        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()) {
            String element = iterator.next();
            System.out.println(element);
            // 在迭代过程中修改集合,会抛出 ConcurrentModificationException
            list.add("D");
        }
    }
}

输出

复制代码
A
Exception in thread "main" java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
    at java.util.ArrayList$Itr.next(ArrayList.java:859)
    at FailFastExample.main(FailFastExample.java:13)
解决方法
  1. 使用迭代器自身的 remove() 方法

    • 如果需要在遍历过程中删除元素,应使用迭代器的 remove() 方法,而不是直接操作集合。
    java 复制代码
    Iterator<String> iterator = list.iterator();
    while (iterator.hasNext()) {
        String element = iterator.next();
        if (element.equals("B")) {
            iterator.remove(); // 安全删除元素
        }
    }
  2. 使用线程安全的集合类

    • 使用 java.util.concurrent 包中的线程安全集合类,如 CopyOnWriteArrayListConcurrentHashMap 等。
    java 复制代码
    import java.util.concurrent.CopyOnWriteArrayList;
    
    public class ConcurrentExample {
        public static void main(String[] args) {
            CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
            list.add("A");
            list.add("B");
            list.add("C");
    
            Iterator<String> iterator = list.iterator();
            while (iterator.hasNext()) {
                String element = iterator.next();
                System.out.println(element);
                // 在迭代过程中修改集合,不会抛出 ConcurrentModificationException
                list.add("D");
            }
        }
    }
  3. 使用 Collections.synchronizedList()Collections.synchronizedSet()

    • 将集合包装为线程安全的集合。
    java 复制代码
    import java.util.Collections;
    import java.util.Iterator;
    import java.util.List;
    
    public class SynchronizedExample {
        public static void main(String[] args) {
            List<String> list = Collections.synchronizedList(new ArrayList<>());
            list.add("A");
            list.add("B");
            list.add("C");
    
            synchronized (list) {
                Iterator<String> iterator = list.iterator();
                while (iterator.hasNext()) {
                    String element = iterator.next();
                    System.out.println(element);
                    // 在迭代过程中修改集合,不会抛出 ConcurrentModificationException
                    list.add("D");
                }
            }
        }
    }
注意事项
  1. 单线程环境

    • 在单线程环境中,Fail-Fast 机制有助于及时发现集合被意外修改的问题。
    • 但需要注意在迭代过程中不要直接修改集合,除非使用迭代器自身的 remove() 方法。
  2. 多线程环境

    • Fail-Fast 机制在多线程环境中可能会导致 ConcurrentModificationException 异常。
    • 应使用线程安全的集合类或同步机制来避免此类问题。
  3. 性能影响

    • Fail-Fast 机制本身对性能的影响较小,主要体现在每次迭代时的 modCount 检查。
    • 但在多线程环境下,频繁的同步操作可能会显著影响性能。
总结
  • Fail-Fast 机制 是 Java 集合框架中用于检测集合在迭代过程中被修改的一种机制。
  • 通过在迭代过程中抛出 ConcurrentModificationException 异常,Fail-Fast 机制可以及时发现不一致的行为,确保集合的完整性和一致性。
  • 在使用 Fail-Fast 机制时,需要注意在迭代过程中不要直接修改集合,除非使用迭代器自身的 remove() 方法。
  • 对于多线程环境,建议使用线程安全的集合类或同步机制来避免 ConcurrentModificationException 异常。

通过合理使用 Fail-Fast 机制,可以提高代码的健壮性和可靠性。

相关推荐
R.lin12 分钟前
Java 8日期时间API完全指南
java·开发语言·python
毕设源码-赖学姐18 分钟前
【开题答辩全过程】以 高校教学质量监控平台为例,包含答辩的问题和答案
java·eclipse
高山上有一只小老虎25 分钟前
翻之矩阵中的行
java·算法
激动的兔子26 分钟前
Windows系统的回收站文件加载慢无法删除该如何解决
windows
西南胶带の池上桜33 分钟前
1.Pytorch模型应用(线性与非线性预测)
人工智能·pytorch·python
火钳游侠39 分钟前
java单行注释,多行注释,文档注释
java·开发语言
code bean1 小时前
【CMake】为什么需要清理 CMake 缓存文件?深入理解 CMake 生成器切换机制
java·spring·缓存
selt7911 小时前
Redisson之RedissonLock源码完全解析
android·java·javascript
RestCloud1 小时前
智能制造的底层基建:iPaaS 如何统一 ERP、MES 与 WMS 的数据流
java·wms·erp·数据传输·ipaas·mes·集成平台
丘狸尾1 小时前
gradio uv无法add
开发语言·python