一般来说
ConcurrentModificationException,如果您尝试在迭代集合时修改集合,则会引发a。例如:
public class Main { public static void main(String[] args) throws Exception { final List<Object> c1 = new ArrayList<Object>(Arrays.<Object>asList(1, 2, 3)); for (Object o: c1) c1.remove(o); }}
会
java.util.ConcurrentModificationException在运行时导致运行,因为我们在迭代列表时正在修改列表(注意:此处仅涉及单个线程)。列表的迭代器检测到此情况,并导致异常。
如果所需修改是从迭代器刚收到非常元素的缺失,就可以达到预期的效果(在单线程情况下!)通过与工作直接迭代。将
for(每个)循环替换为:
final Iterator<Object> iterator = c1.iterator();while (iterator.hasNext()) { final Object o = iterator.next(); if (satisfiesSomeCriterion(o)) iterator.remove();}
但是,这并不适用于所有修改。例如,添加将不起作用。以下代码仍然失败:
for (Object o: c1) c1.add(Integer.valueOf(((Integer)o).intValue() + 10));
如果基础集合是
List,则可以使用a
ListIterator代替普通的迭代器来解决此限制:
final ListIterator<Integer> iterator = c1.listIterator();while (iterator.hasNext()) { final Integer o = iterator.next(); if (satisfiesSomeCriterion(o)) iterator.add(Integer.valueOf(o.intValue() + 10);}
但是请注意,这与上面给出的代码(插入元素的其他位置)不同。还要注意,这
ListIterator.add是一个可选方法;一个实现可能
UnsupportedOperationException在调用时抛出一个。
上述所有内容仅适用于单线程情况。如果您尝试在没有适当同步的情况下从多个线程同时访问同一集合,则会出现一系列新问题,因为这不仅可能导致
ConcurrentModificationException迭代线程中出现s,而且可能破坏集合内部数据的完整性。结构。
您可以做几件事:
- 使用并发感知集合(例如
CopyOnWriteArrayList
您已经提到的集合) - 通过
Collections.synchronizedList
(...Set
,...Whatever
)包装集合。但是请注意,在这种情况下,您仍然有责任针对迭代提供适当的锁定规则。有关详细信息,请参见此答案。 - 在将原始集合传递给后台作业之前,先对其进行备份(并确保后台作业是使用该副本的唯一线程)
- 通过
synchronized
块保护集合的所有使用(例如,将集合本身用作“监视”对象,尽管更好:使用专用的监视对象)。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)