MST
星途 面试题库

面试题:Java ArrayList迭代器与并发修改异常

假设有一个多线程环境,多个线程同时对一个ArrayList进行操作,其中既有添加元素的操作,也有使用迭代器遍历的操作。请分析可能会出现什么问题?如何解决这个问题?请结合代码示例说明,例如使用`CopyOnWriteArrayList`的解决方案,并阐述`CopyOnWriteArrayList`的原理。
29.9万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

可能出现的问题

在多线程环境下,多个线程同时对ArrayList进行添加元素和使用迭代器遍历操作时,可能会抛出ConcurrentModificationException异常。这是因为当一个线程在遍历ArrayList时,另一个线程对其进行了结构上的修改(如添加元素),导致迭代器感知到集合的结构发生了变化,从而抛出该异常。

解决方案 - 使用CopyOnWriteArrayList

CopyOnWriteArrayList是Java并发包中提供的线程安全的List实现。以下是使用CopyOnWriteArrayList的代码示例:

import java.util.Iterator;
import java.util.concurrent.CopyOnWriteArrayList;

public class CopyOnWriteArrayListExample {
    public static void main(String[] args) {
        CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();

        // 启动添加元素的线程
        Thread addThread = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                list.add("Element " + i);
            }
        });

        // 启动遍历的线程
        Thread iterateThread = new Thread(() -> {
            Iterator<String> iterator = list.iterator();
            while (iterator.hasNext()) {
                System.out.println(iterator.next());
            }
        });

        addThread.start();
        iterateThread.start();

        try {
            addThread.join();
            iterateThread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

CopyOnWriteArrayList的原理

  1. 写时复制:当对CopyOnWriteArrayList进行写操作(如添加、删除元素)时,它会先复制一份当前的数组,然后在新的数组上进行修改操作,最后将原数组引用指向新的数组。这样做可以保证在写操作时,读操作仍然可以基于原数组进行,不会受到写操作的影响。
  2. 迭代器CopyOnWriteArrayList的迭代器是基于数组的快照创建的,在迭代过程中不会抛出ConcurrentModificationException。因为迭代器遍历的是创建迭代器时数组的快照,而不是实时的数组,所以即使其他线程对数组进行了修改,迭代器也不会感知到,从而避免了异常的抛出。

综上所述,CopyOnWriteArrayList通过写时复制的机制,提供了一种线程安全的List实现,适用于读多写少的场景。