原代码如下:
原因: jdk5.0以上的for-each也是利用内部的iterator来遍历集合的(跟以前的iterator一样) 获得的Iterator是一个内部类产生的迭代器,这个迭代器在调用next方法时,会检查列表是否被修改过,如果被修改过,就会抛出 ConcurrentModificationException异常。进一步说,当使用 fail-fast iterator 对 Collection 或 Map 进行迭代操作过程中尝试直接修改 Collection / Map 的内容时,即使是在单线程下运xi,java.util.ConcurrentModificationException 异常也将被抛出。Iterator 是工作在一个独立的线程中,并且拥有一个 mutex 锁。 Iterator 被创建之后会建立一个指向原来对象的单链索引表,当原来的对象数量发生变化时,这个索引表的内容不会同步改变,所以当索引指针往后移动的时候就找不到要迭代的对象,所以按照 fail-fast 原则 Iterator 会马上抛出 java.util.ConcurrentModificationException 异常。所以 Iterator 在工作的时候是不允许被迭代的对象被改变的。但你可以使用 Iterator 本身的方法 remove() 来删除对象,Iterator.remove() 方法会在删除当前迭代对象的同时维护索引的一致性。
有意思的是如果你的 Collection / Map 对象实际只有一个元素的时候, ConcurrentModificationException 异常并不会被抛出。这也就是为什么在 javadoc 里面指出: it would be wrong to write a program that depended on this exception for its correctness: ConcurrentModificationException should be used only to detect bugs.
解决方法: 在Map或者Collection的时候,不要用它们的API直接修改集合的内容,如果要修改可以用Iterator的remove()方法
由于for-each的写法,使我们无法获得iterator对象,所以这种遍历方式不能进行删除操作。只好改成了比较土的方法实现了List list = ...;
for(Iterator iter = list.iterator(); iter.hasNext();) {
Object obj = iter.next();
...
if(***) {
list.remove(obj);
}
}
在执行了remove方法之后,再去执行循环,iter.next()的时候,报java.util.ConcurrentModificationException(当然,如果remove的是最后一条,就不会再去执行next()操作了)
下面来看一下源码
public interface Iterator
这里有两个remove方法
接下来来看看AbstractList
public abstract class AbstractList
remove(Object o)在ArrayList中实现如下:
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
private void fastRemove(int index) {
modCount++; //只增加了modCount
....
}
所以,产生ConcurrentModificationException的原因就是:
执行remove(Object o)方法之后,modCount和expectedModCount不相等了。然后当代码执行到next()方法时,判断了checkForComodification(),发现两个数值不等,就抛出了该Exception。
要避免这个Exception,就应该使用Iterator的remove()方法。
相关推荐
Java.util.ConcurrentModificationException 异常问题详解 ConcurrentModificationException 异常是 Java 中一个常见的异常,它发生在 Iterator 遍历集合时,集合同时被修改引起的异常。在 Java 中,集合类如 ...
通过使用正确的数据结构、同步机制或者线程安全的集合,可以有效地避免`java.util.ConcurrentModificationException`,保证代码的稳定性和可靠性。在实践中,应始终考虑并发控制和线程安全,特别是在处理共享资源时...
总的来说,避免 `java.util.ConcurrentModificationException` 的关键在于正确管理和同步集合访问。在遍历集合时,避免同时进行修改操作,或者使用并发安全的集合类。对于需要修改的情况,优先选择使用迭代器的 `...
其中一个典型的问题就是java.util.ConcurrentModificationException异常,通常在遍历集合时试图修改集合内容时抛出。Java提供了几种解决方案来应对这种情况,以下是详细的解决方法和知识点: ### 并发集合的使用 ...
### Java.util.concurrent 系列文章知识点总结 #### 一、引言 随着多核处理器的普及,多线程编程已成为现代软件开发中的一个重要组成部分。Java 5 引入了 `java.util.concurrent` 包,该包提供了丰富的 API 来简化...
在Java编程中,`ConcurrentModificationException`是一个常见的运行时异常,主要出现在多线程环境下对集合类(如List、Set、Map等)进行并发修改时。然而,这个异常不仅限于多线程环境,即使在单线程中,如果在遍历...
在鸿蒙开发过程中遇到的`ConcurrentModificationException`异常问题及...在鸿蒙(HarmonyOS)的多线程开发中,正确的选择合适的集合和方法来避免`ConcurrentModificationException`异常是保证应用稳定性的重要步骤。
import java.util.concurrent.CopyOnWriteArrayList; public class ConcurrentModificationExample { public static void main(String[] args) { CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList...
避免这种问题的方法是始终确保对象在使用前已经被初始化,或者在访问其成员之前进行非null检查。 二、数组越界异常(ArrayIndexOutOfBoundsException) 当试图访问数组的一个不存在的索引时,会发生此异常。程序员...
例如`Collections.unmodifiable*`方法创建的集合和`java.util.Collections`类中的`emptyList()`、`emptySet()`等。这些集合一旦创建就不能修改,因此天然线程安全。 示例代码: ```java import java.util.*; ...
- `java.util.Iterator`的改进:支持`remove()`操作,避免抛出`ConcurrentModificationException`。 ### 4. 性能优化 JDK 1.6对编译器和垃圾收集器进行了优化,提高了运行效率,例如: - **Server VM的改进**: ...
import java.util.ArrayList; import java.util.Iterator; public class IteratorExample { public static void main(String[] args) { ArrayList<String> names = new ArrayList(); names.add("Ada Lovelace");...
4. 如果需要更复杂的并发控制,可以使用`java.util.concurrent.locks`包下的Lock接口及其实现,如ReentrantLock,配合`tryLock()`方法进行细粒度的锁控制。 总的来说,处理多线程环境中的Java集合类时,开发者需要...
ConcurrentModificationException异常是在Java编程中处理集合时经常会遇到的一个问题。当集合正在被迭代时,如果...希望这些方法能够帮助你有效解决在Java集合操作中遇到的ConcurrentModificationException异常问题。
通过在代码块中使用synchronized关键字或java.util.concurrent.locks包中的锁,可以实现对资源的互斥访问,从而避免并发修改异常的发生。 6. 需要注意的是,使用同步块或锁虽然可以解决并发修改的问题,但这可能会...
Java 的并发包 java.util.concurrent 提供了线程安全的集合类,如 CopyOnWriteArrayList 或 ConcurrentHashMap 等。这些集合类内部实现了线程安全的迭代和修改机制。因此,即便在迭代过程中发生修改,也不会抛出 ...
下载`concurrent.rar`文件,你将有机会学习到这些关键概念的实际示例和使用方法,进一步加深对Java并发编程的理解。通过深入研究,你可以编写出更加高效、安全的多线程程序,提升你的Java编程技能。
为了避免这种问题,通常建议在迭代时不要直接修改集合,或者使用`ListIterator`的`add()`方法添加元素。 6. **`ListIterator`与`Iterator`的区别** `ListIterator`是`Iterator`的一个子接口,专门为`List`类型的...