欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java ConcurrentModificationException 异常

程序员文章站 2022-04-18 17:18:38
...

Java 许多集合都是非线程安全的,如果对它们进行并发操作会引发 fail - fast 机制,抛出 ConcurrentModificationException 异常。

我们先来看看这个异常吧。

源码如下:

public class ConcurrentModificationException extends RuntimeException {
    private static final long serialVersionUID = -3666751008965953603L;

    public ConcurrentModificationException() {
    }


    public ConcurrentModificationException(String message) {
        super(message);
    }

    public ConcurrentModificationException(Throwable cause) {
        super(cause);
    }


    public ConcurrentModificationException(String message, Throwable cause) {
        super(message, cause);
    }
}

源码似乎没什么特别之处。

我们还是直接引入一个例子吧:

假设我们要判断集合里面有没有 "Jerry" 这个元素,如果有,就往集合里添加一个 "Sad" 元素。代码如下:

import java.util.ArrayList;
import java.util.Iterator;

public class Test {

    public static void main(String[] args) {
        ArrayList<String> array = new ArrayList<String>();

        // 创建并添加元素
        array.add("hello");
        array.add("Jerry");
        array.add("java");

        Iterator it = array.iterator();
        while (it.hasNext()) {
            String s = (String) it.next();
            if ("Jerry".equals(s)) {
                array.add("Sad");
            }
        }
    }
}

上面代码会不出意料地抛出 ConcurrentModificationException 异常。

1. 异常解释

ConcurrentModificationException:当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常。

产生的原因:

迭代器是依赖于集合而存在的,在条件判断成功之后,在集合的中新添加了元素,而迭代器却不知道,所以就报错了,这个叫并发修改异常。

简单描述就是:迭代器遍历元素的时候,是不能修改集合的。

如何解决呢?
  • 先用迭代器迭代元素,再用迭代器修改元素;

  • 遍历集合查找元素,然后通过集合修改元素(普通 for)。

2. 下面用两种方法解决这个异常

import java.util.ArrayList;

public class Test {

    public static void main(String[] args) {
        ArrayList<String> array = new ArrayList<String>();

        // 创建并添加元素
        array.add("hello");
        array.add("Jerry");
        array.add("java");

        // 方式1:先用迭代器迭代元素,再用迭代器修改元素.
        // 而Iterator迭代器却没有添加功能,所以我们使用其子接口ListIterator
        ListIterator lit = array.listIterator();
        while (lit.hasNext()) {
            String s = (String) lit.next();
            if ("Jerry".equals(s)) {
                lit.add("Sad");
            }
        }
        System.out.println("list1:" + array);


        // 方式2:遍历集合查找元素,遍历集合修改元素(普通 for)。
        for (int x = 0; x < array.size(); x++) {
            String s = (String) array.get(x);
            if ("Jerry".equals(s)) {
                array.add("Sad");
            }
        }

        System.out.println("list2:" + array);

        // 增强 for 循环不能解决问题。
        // 增强 for 循环写的话会报同样的错误,因为它本身就是用来替代迭代器的。
        /*for (String s : array) {
            if ("world".equals(s)) {
                array.add("javaee");
            }
        }
        System.out.println("list3:" + array);*/
    }
}