我正在处理间歇性的,很难在一大块遗留代码中重现ConcurrentModificationException
:
class LegacyCode {
private final WeakHashMap<A, B> mItems = new WeakHashMap<A, B>();
public void someWork() {
final List<A> copy = new LinkedList<A>();
for (final A item : mItems.keySet()) {
copy.add(item);
}
for (final A item : copy) {
item.someMethod();
}
}
public void addItem(final A item) {
mItems.put(item, new B());
}
public void removeItem(final A item) {
mItems.remove(item);
}
}
CME正在投入:
for (final A item : mItems.keySet()) {
copy.add(item);
}
我不完全确定为什么我们以这种方式创建copy
。抛出CME是因为在for-each循环运行时调用了addItem(A)
或removeItem(A)
。
问题
我对CME为什么被抛出正确的理解?
如果我用以下代码替换for-each循环,我会避免CME吗?
final List<A> copy = new LinkedList<A>(mItems.keySet());
此更改是否等同于我们将要替换的for-each循环?据我所知,两个片段都在mItems.keySet()
中创建了copy
的浅表副本。
答案 0 :(得分:2)
我对CME为什么被抛出正确的理解?
绝对。这正是发生的事情。
如果用以下内容替换for-each循环,我会避免使用CME吗?
final List<A> copy = new LinkedList<A>(mItems.keySet());
不,你不会,因为LinkedList<A>
的构造函数会有类似的循环。所以你说这个改变将等同于我们将要替换的for-each循环是正确的。
就修复此问题而言,Java标准库中的WeakHashMap
类没有现成的并发替换。您可以通过使addItem
和removeItem
同步,并在构建copy
的循环周围添加同步块,以明显的方式解决此问题。您还可以在不使用代码中的synchronized
的情况下查看解决此问题的third-party collections。