繁体   English   中英

来自称为asynctask的静态方法的并发修改异常

[英]Concurrent modification exception from a static method that being called asynctask

我有一个静态方法,该方法是从doInBackGround()中的Asynctask调用的

该方法中包含以下部分代码:

    ArrayList<Message> messagesList = new ArrayList<Message>();
    if (!clearList) {
        messagesList.addAll(messages.getMessagesList());
            for (Message msg : messagesList) {
                if (msg.getId().length() == 0) {
                    messagesList.remove(msg);
                }
        }
    }

有时会抛出“并发修改异常”,我尝试将方法声明为“已同步”,但它仍然无济于事,而且我无法声明该块已同步,因为它是静态方法,没有“ this”引用。

如果需要启动另一个异步任务,我也曾尝试停止运行该异步任务,但这也无济于事。

帮助表示赞赏。

这与同步无关。 您正在使用迭代器遍历messagesList ,然后在迭代过程中使用remove进行修改。 您不能这样做,因为如果在迭代过程中修改了列表,则ArrayList的迭代器会失败。 文档

此类的iteratorlistIterator方法返回的iterator快速失败的 :如果在创建迭代器之后的任何时间以任何方式对列表进行结构修改,则除了通过迭代器自己的removeadd方法之外,迭代器都会抛出ConcurrentModificationException

增强的for循环只是使用Iterator语法糖,因此您可以使它显式,然后使用迭代器的remove方法

Iterator<Message> it = messagesList.iterator();
while (it.hasNext()) {
    if (it.next().getId().length == 0) {
       it.remove();
    }
}

或者,你可以只使用一个简单for落后和索引运行进入循环ArrayList (因为get(int)是上的廉价和固定时间操作ArrayList ,这是不是所有的真正的List S):

int index;
for (index = messagesList.length - 1; index >= 0; --index) {
    if (messagesList.get(index).getId().length == 0) {
       messagesList.remove(index);
    }
}

ArrayList返回的迭代器本质上是fail-fast

此类的迭代器和listIterator方法返回的迭代器是fail-fas :如果在创建迭代器后的任何时间以任何方式对列表进行结构修改,则除了通过迭代器自己的remove或add方法外,该迭代器都会抛出ConcurrentModificationException 因此,面对并发修改,迭代器会快速干净地失败,而不会在未来的不确定时间内冒任意,不确定的行为的风险。

您可以调用iterator.remove(); 并基于迭代器显式而非隐式地更改循环。

ArrayList<Message> messagesList = new ArrayList<Message>();
    if (!clearList) {
        messagesList.addAll(messages.getMessagesList());
        for (ListIterator<Message> iterator = messagesList.listIterator();iterator.hasNext();) {
            Message message = iterator.next();
            if (message.getId().length() == 0) {
                iterator.remove();
            }
        }
    }

参考文献:

  1. 每次循环
  2. ArrayList Java文档
 for (Message msg : messagesList) {
                if (msg.getId().length() == 0) {
                    messagesList.remove(msg);
                }
        }

在这段代码中,您一次使用messagesList ,同时还从messagesList删除数据,这就是您遇到错误并发修改异常的原因

这里是解决您的问题的更好方法。 将所有数据复制到一个数组列表中以从主列表中删除和删除所有数据。

Message removeMsg = new ArrayList<Message>();
 for (Message msg : messagesList) {
                    if (msg.getId().length() == 0) {
                        removeMsg.add(msg);
                    }
            }

messagesList.removeAll(removeMsg);

for循环可能会修改要对其进行迭代的列表。 这是导致异常的原因。 修改是基于条件的事实是其并非始终都发生的原因,因为列表不一定需要修改。

使用Iterator是一种可能的解决方案,它提供了remove()方法。

您应该为此类使用Synchronize关键字,因为静态方法不属于任何实例

-您的问题是与同步有关,但ConcurrentModification你所面临的问题是用来保护收集采取的错误类型的对象。

例如:

防止Cat对象进入Dog类型的集合。

-您可以使用Iterator解决此问题

ArrayList<Message> messagesList = new ArrayList<Message>();

Iterator<Message> itr = messagesList.iterator();

while(itr.hasNext()){

 Message m = itr.next();

 itr.remove();   // Its remove() method of Iterator NOT ArrayList's

}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM