java.util.ConcurrentModificationException
异常是在使用迭代器(Iterator)遍历集合(如 ArrayList、HashSet 等)的过程中,如果通过非迭代器自身的方法对集合的结构进行了修改(比如添加、删除元素),则会抛出此异常。这是因为迭代器在遍历过程中维护了一个“modCount”值,用于检测集合结构是否被修改。如果检测到修改(即集合的 modCount 值与迭代器预期的 modCount 值不一致),则会抛出
ConcurrentModificationException
。
问题分析
当在遍历集合的同时,使用非迭代器的方法修改集合(如直接调用集合的 add
或 remove
方法),迭代器无法感知到这些变化,因此在下一次迭代时可能会遇到不一致的状态,从而抛出 ConcurrentModificationException
。
报错原因
- 在使用迭代器遍历集合时,通过非迭代器的方法修改了集合的结构。
- 并发环境中,多个线程同时修改同一个集合,导致迭代器检测到不一致的状态。
解决思路
- 使用迭代器的
remove
方法:如果需要在遍历过程中删除元素,应该使用迭代器自身的remove
方法,而不是集合的remove
方法。 - 使用并发集合:如果需要在多线程环境中修改集合,应该使用线程安全的并发集合,如
CopyOnWriteArrayList
、ConcurrentHashMap
等。 - 同步块:如果必须使用非线程安全的集合,并且需要在多线程环境中访问,可以通过同步块(synchronized blocks)来确保线程安全。
解决方法
1. 使用迭代器的 remove
方法
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String element = iterator.next();
if (someConditionToRemove(element)) {
iterator.remove(); // 使用迭代器的 remove 方法删除元素
}
// ... 其他操作
}
2. 使用并发集合
例如,使用 CopyOnWriteArrayList
:
List<String> list = new CopyOnWriteArrayList<>();
// ... 添加元素到 list
// 由于 CopyOnWriteArrayList 是线程安全的,可以在多线程环境下安全修改
// 但请注意,写操作(如 add、remove)可能会产生较大的开销
3. 使用同步块
下滑查看解决方法
如果需要在多线程环境中使用非线程安全的集合,并且性能开销不是主要考虑因素,可以使用同步块:
List<String> list = new ArrayList<>();
// ... 添加元素到 list
synchronized (list) {
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String element = iterator.next();
// ... 进行某些操作
// 如果需要删除元素,使用迭代器的 remove 方法
if (someConditionToRemove(element)) {
iterator.remove();
}
}
// ... 可能还有其他的集合修改操作
}
总结
ConcurrentModificationException
异常通常发生在遍历集合的同时修改集合结构时。为了避免此异常,应该使用迭代器的 remove
方法来删除元素,或者使用线程安全的并发集合,或在多线程环境中使用同步块来确保线程安全。选择哪种方法取决于具体的场景和需求。