ArrayList同时读写造成java.util.ConcurrentModificationException异常

在ArrayList同时读写时,会造成java.util.ConcurrentModificationException异常。该读写包括同时调用ArrayList的add、remove、size、addAll、set、get等方法,都会报该异常。

该异常的本质是调用上述方法List中modCount就会变化,如果这个modCount和exceptedModCount不一致,就会抛出异常。具体的场景有以下几种:使用forEach遍历时删除元素、多线程同时读写。

那如何避免该问题呢?遍历时删除元素,不要使用forEach遍历即可。 foreach方式遍历元素的时候会生成iterator,然后使用iterator遍历。同时iterator会保存一个expectedModCount参数。该参数表示List中修改元素的次数。如果在遍历过程中删除元素,List中modCount就会变化,如果modCount和exceptedModCount不一致,就会抛出异常。

如果使用iterator的remove方法则会正常,因为iterator的remove方法会在内部调用List的remove方法,但是会修改excepedModCount的值,因此会正常运行。以下是使用遍历同时删除元素不报异常的实例:

1、倒序遍历 List ,如果找到元素,则使用 remove 方法进行移除:

List<String> list = new ArrayList<>();
list.add("第一代码");
list.add("知音简历");
list.add("免费简历");
list.add("简历模板");
list.add("免费范文");
for (int i = list.size() - 1; i > 0; i--) {
    if("简历模板".equals(list.get(i))){
        list.remove(i);
    }
}
System.out.println(list);

2、使用 Iterator ,顺序向下,如果找到元素,则使用 remove 方法进行移除:

List<String> list = new ArrayList<>();
list.add("第一代码");
list.add("知音简历");
list.add("免费简历");
list.add("简历模板");
list.add("免费范文");
// 获取迭代器
Iterator<String> it = list.iterator();
while(it.hasNext()){
    String str = it.next();
    if("第一代码".equals(str)){
        it.remove();
    }
}
System.out.println(list);

3、正序遍历 List ,如果找到元素,则使用 remove 方法进行移除,然后进行索引自减:

List<String> list = new ArrayList<>();
list.add("第一代码");
list.add("知音简历");
list.add("免费简历");
list.add("简历模板");
list.add("免费范文");
for (int i = 0; i < list.size(); i++) {
    if("知音简历".equals(list.get(i))){
        list.remove(i);
        i--;
    }
}
System.out.println(list);

4、使用jdk1.8新增的Stream流操作:

List<String> list = new ArrayList<>();
list.add("第一代码");
list.add("知音简历");
list.add("免费简历");
list.add("简历模板");
list.add("免费范文");
// 筛选出不是“第一代码” 的集合
list = list.stream().filter(e -> !"第一代码".equals(e)).collect(Collectors.toList());
System.out.println("method4|list=" + list);

以下是使用多线程读写不报异常的实例,可添加synchronized 同步锁防止异常:

List<String> list = new ArrayList<>();

    synchronized (list) {
        list.add("第一代码");
        list.add("知音简历");
        list.add("免费简历");
        list.add("简历模板");
        list.add("免费范文");
        System.out.println(list.get(0));
    }

    synchronized (list) {
        for (int i = list.size() - 1; i > 0; i--) {
            if ("简历模板".equals(list.get(i))) {
                list.remove(i);
            }
        }
        System.out.println(list);
    }

 

 

发表回复

后才能评论