面试题:你遇到过 ConcurrentModificationException 错误吗?它是如何产生的?

ConcurrentModificationException 是 Java 中常见的运行时异常之一,通常在不当修改集合(如 List、Set 或 Map)时抛出。这种错误特别容易在多线程环境下出现,但单线程程序也可能触发它。

如何产生

  1. 单线程环境:当一个方法检测到正在进行的迭代与预期的结构不符时,会抛出此异常。例如,在使用迭代器遍历集合的同时,直接通过集合的方法(如 add()remove()等)修改该集合,而不是使用迭代器自己的方法来修改集合,就会导致这个异常。
  2. 多线程环境:如果一个线程正在迭代一个集合,而另一个线程试图修改这个集合(添加、删除元素等),也会抛出 ConcurrentModificationException 异常。这是因为默认情况下大多数集合类(如 ArrayListHashMap 等)都不是线程安全的,它们没有对并发修改进行同步处理。

示例代码(单线程)

import java.util.*;

public class Test {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);

        for (Integer i : list) { // 使用迭代器隐式遍历
            if (i == 2) {
                list.remove(i); // 这里会抛出 ConcurrentModificationException
            }
        }
    }
}

解决方案

  • 使用迭代器的 remove 方法:在需要修改集合的地方,应该使用迭代器本身的 remove() 方法。
  Iterator<Integer> it = list.iterator();
  while(it.hasNext()){
      Integer i = it.next();
      if(i == 2){
          it.remove(); // 正确的方式
      }
  }
  • 使用并发集合类:对于多线程环境,可以使用线程安全的集合类,比如 CopyOnWriteArrayListConcurrentHashMap 等。
  • 手动同步:也可以通过对集合进行显式的同步控制来避免这个问题,但是这种方式比较繁琐且容易出错。

理解并正确处理 ConcurrentModificationException 对于编写高效且无误的Java应用程序至关重要。无论是通过选择合适的集合类型还是合理设计代码逻辑,都是解决这一问题的有效手段。

THE END
喜欢就支持一下吧
点赞6 分享