原代码如下:
原因: 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编程中,`ConcurrentModificationException`是一个常见的运行时异常,主要出现在多线程环境下对集合类(如List、Set、Map等)进行并发修改时。然而,这个异常不仅限于多线程环境,即使在单线程中,如果在遍历...
避免这种问题的方法是始终确保对象在使用前已经被初始化,或者在访问其成员之前进行非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集合类时,开发者需要...
下载`concurrent.rar`文件,你将有机会学习到这些关键概念的实际示例和使用方法,进一步加深对Java并发编程的理解。通过深入研究,你可以编写出更加高效、安全的多线程程序,提升你的Java编程技能。
为了避免这种问题,通常建议在迭代时不要直接修改集合,或者使用`ListIterator`的`add()`方法添加元素。 6. **`ListIterator`与`Iterator`的区别** `ListIterator`是`Iterator`的一个子接口,专门为`List`类型的...
`java.util.concurrent.ForkJoinPool`和`java.util.concurrent.RecursiveTask`是其核心类。 7. **非阻塞堆栈跟踪(Non-blocking Stack Traces)** 当线程处于等待状态时,Java 7可以生成不包含阻塞信息的堆栈跟踪...
Java并发工具包(java.util.concurrent)是Java编程中不可或缺的一部分,它为多线程环境提供了高效、安全且易用的工具。这个包包含了各种类和接口,帮助开发者编写高效的并发程序,避免了直接操作线程所带来的复杂性...
4. `java.util.concurrent.atomic`包:提供了一组原子类,如`AtomicInteger`、`AtomicLong`等,它们的原子操作在多线程环境中避免了锁的开销。 遵循以上规则,可以显著提高多线程程序的并发性能和稳定性。然而,...
首先,Java中的`Collections.unmodifiable*`方法是创建只读集合的常用方式。例如,`Collections.unmodifiableList()`, `Collections.unmodifiableSet()`, 和 `Collections.unmodifiableMap()`分别用于创建只读列表、...
Arrays.asList 方法返回的 List 并不是我们常用的 java.util.ArrayList,而是 Arrays 的静态内部类 java.util.Arrays.ArrayList,该类继承自抽象类 java.util.AbstractList,但没有实现 add 方法,默认抛出 java....
- **java.util.concurrent.atomic包**:包含`AtomicInteger`, `AtomicLong`等类,提供在不使用锁的情况下实现原子操作的方法。 6. **线程池** - **线程池原理**:如何管理线程的创建、复用和销毁,以及任务的提交...
当使用`Arrays.asList()`方法将数组转换为列表时,返回的是`java.util.Arrays.ArrayList`,这是一个内部静态类,不支持添加或删除元素。如果需要一个可变的ArrayList,应使用构造函数创建新的ArrayList实例,如: ...