前言

Android开发中,使用ArrayList出现 Exception in thread “main” java.util.ConcurrentModificationException异常是比较常见的,部分日志如下:

Exception in thread "main" java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
    at java.util.ArrayList$Itr.next(ArrayList.java:851)

记录一下相关知识,方便自己查阅。

本文内容大分部来源参考文。

正文

当checkForComodification()方法检测到对象的并发修改元素时,这是不允许的,因此会抛出ConcurrentModificationException。

原因

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

迭代器遍历元素的时候,通过集合是不能修改元素的。

下面分单线程和多线程分析。

单线程

List<String> myList = new ArrayList<String>();
myList.add("1");
myList.add("2");
myList.add("3");
myList.add("4");
myList.add("5");

下面三个例子遍历时并修改数据都会ConcurrentModificationException异常。

问题
例子
for (Iterator<String> it = myList.iterator(); it.hasNext(); ) {
    String value = it.next();
    if (value.equals("3")) {
        myList.remove(value);
    }
}
例子2
for (String value : myList) {
    if (value.equals("3")) {
        myList.remove(value);
    }
}
例子3
Iterator<String> it = myList.iterator();
while (it.hasNext()) {
    String value = it.next();
    if (value.equals("3")) {
        myList.remove(value);
    }
}
解决方式
方式1

通过it移除

for (Iterator<String> it = myList.iterator(); it.hasNext(); ) {
    String value = it.next();
    if (value.equals("3")) {
        it.remove(); 
    }
}
方式2

创建临时list记录需要移除的,然后统一移除。

List<String> templist = new ArrayList<String>();
for (String value : myList) {
    if (value.equals("3")) {
        templist.add(value);
    }
}
myList.removeAll(templist);
方式3

ArrayList改为CopyOnWriteArrayList

List<String> myList = new CopyOnWriteArrayList<>();
myList.add("1");
myList.add("2");
myList.add("3");
myList.add("4");
myList.add("5");

Iterator<String> it = myList.iterator();
while (it.hasNext()) {
    String value = it.next();
    if (value.equals("3")) {
        myList.remove(value);
    }
}
方式4

不使用Iterator进行遍历,需要注意的是自己保证索引正常

for ( int i = 0; i < myList.size(); i++) {
    String value = myList.get(i);
    if (value.equals( "3")) {
        myList.remove(value); 
        i--; // 因为位置发生改变,所以必须修改i的位置
    }
}

多线程

单线程有问题,多线程也是存在的。

比如一个线程中添加元素,一个线程中删除元素。

解决方式,使用上面的方式4才有效。亲测。

List<String> myList = new CopyOnWriteArrayList<>();
myList.add("1");
myList.add("2");
myList.add("3");
myList.add("4");
myList.add("5");
new Thread(() -> {
    for (String string : myList) {
        Log.d(TAG, "run delete string : " + string);
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}).start();
new Thread(() -> {
    for (int i = 0; i < myList.size(); i++) {
        String value = myList.get(i);
        if (value.equals("3")) {
            myList.remove(value);
            i--; 
        }
    }
}).start();

参考文章

  1. Java ConcurrentModificationException 异常分析与解决方案

相关文章

暂无评论

none
暂无评论...