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

时间:2012-10-30 11:08:37

标签: java android android-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);
                }
        }
    }

有时会抛出&#39;并发修改例外&#39;,我已经尝试将该方法声明为&#39; synchronized&#39;但它仍然没有帮助,我不能声明块同步,因为它是一个静态的方法,没有&#39;这个&#39;参考

如果我需要启动另一个,我也尝试停止运行asynctask,但它也没有帮助。

帮助表示赞赏。

6 个答案:

答案 0 :(得分:5)

这与同步无关。您正在使用迭代器循环遍历messagesList,但在迭代期间使用remove来修改它。您不能这样做,因为ArrayList的迭代器在迭代期间修改列表时会失败。来自the docs

  

此类的iteratorlistIterator方法返回的迭代器是 fail-fast :如果在创建迭代器后的任何时候对列表进行结构修改,则任何除了通过迭代器自己的removeadd方法之外,迭代器将抛出ConcurrentModificationException

你的enhanced for loop只是使用Iterator的语法糖,所以你可以将它显式化,然后使用迭代器的remove method

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);
    }
}

答案 1 :(得分:3)

ArrayList返回的迭代器性质为fail-fast

  

此类的迭代器和listIterator方法返回的迭代器是fail-fas t:如果在创建迭代器之后的任何时候对列表进行结构修改,除非通过迭代器自己的删除或添加方法,迭代器将抛出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. The For-Each Loop
  2. ArrayList Java docs

答案 2 :(得分:3)

 for (Message msg : messagesList) {
                if (msg.getId().length() == 0) {
                    messagesList.remove(msg);
                }
        }

在此代码中,您同时使用messagesList来删除messagesList中的数据,这就是您遇到错误的原因并发修改例外 ..

这是解决问题的更好方法。将所有数据复制到一个arraylist中以删除&amp;从主列表中删除所有数据。

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

messagesList.removeAll(removeMsg);

答案 3 :(得分:2)

for循环可能会修改迭代的列表。这是异常的原因。修改基于条件的事实是它不会一直发生的原因,因为列表不一定被修改。

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

答案 4 :(得分:0)

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

答案 5 :(得分:0)

- 您的问题与同步相关联,但您遇到的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

}