ConcurrentModificationException解决方法

3

我有一个问题。同时访问Vector时,我会得到一个ConcurrentModificationException。我为所有的向量迭代添加了同步块,但可能忘记了其中一个或存在其他漏洞。

问题在于,在错误的堆栈跟踪中,错误显示为对Vector.retainAll()方法的调用,该方法是同步的。我如何猜测参与冲突的另一点是什么?

提前致谢。

 08-24 13:37:25.968: ERROR/AndroidRuntime(6582): java.util.ConcurrentModificationException
 08-24 13:37:25.968: ERROR/AndroidRuntime(6582):     at java.util.AbstractList$SubAbstractList.listIterator(AbstractList.java:320)
 08-24 13:37:25.968: ERROR/AndroidRuntime(6582):     at java.util.AbstractList$SubAbstractList.iterator(AbstractList.java:307)
 08-24 13:37:25.968: ERROR/AndroidRuntime(6582):     at java.util.AbstractCollection.contains(AbstractCollection.java:128)
 08-24 13:37:25.968: ERROR/AndroidRuntime(6582):     at java.util.Collections$SynchronizedCollection.contains(Collections.java:432)
 08-24 13:37:25.968: ERROR/AndroidRuntime(6582):     at java.util.AbstractCollection.retainAll(AbstractCollection.java:319)
 08-24 13:37:25.968: ERROR/AndroidRuntime(6582):     at java.util.Vector.retainAll(Vector.java:856)

Collection#SynchronizedCollection在迭代支持集合时不会锁定其后备集合。请阅读文档 - Prince John Wesley
2个回答

4
检查代码是否在迭代向量时进行了结构修改(添加或删除) - 这很可能是导致 CME 的原因。使用迭代器进行此类修改以避免 CME。
void unsafeMod(Vector data) {
    for (Object o : data) {
        if (o != null) {
            data.remove(o); // may cause CME
        }
    }
}

我也赞同使用ArrayList而不是Vector的建议


1
实际上,这是获得CME的唯一方法。多个线程可能涉及其中,但这并不改变事实。类似,但不是完全重复的https://dev59.com/-nRB5IYBdhLWcg3wgHar#602660。 - Robin

1

只要不让除了持有向量的对象之外的任何人访问该向量,这是确保在迭代期间没有其他人修改它的唯一方法。

从持有对象的方法中返回和传递向量的副本,或者返回/传递一个不可修改的版本(使用Collections.unmodifiableList())。当然,返回一个不可修改的列表将破坏执行retainAll调用的代码。

附注:Vector已经过时,不应再使用。正如你刚刚注意到的,它的同步性并不能保护你免受并发访问错误的影响。因此,使用ArrayList更好。


非常抱歉,我最初投了反对票,因为CME并不是一个特定的线程相关问题,我本来想发表评论以此说明。但在仔细查看问题后,意识到错误发生在retainAll()方法中,我意识到在这种情况下它是一个线程问题,不幸的是,由于时间过去太久,我无法更改我的投票。 - Robin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接