今天改bug,其中有个实现是要对map进行循环,然后有删除操作,代码如下:
Iterator<ListItem> iter = ItemMap.keySet.iterator();
while(iter.hasNext()){
ListItem it = iter.next();
//...一些逻辑操作
ItemMap.remove(it);
}
结果运行报ConcurrentModificationException,代码修改为:
Iterator<ListItem> iter = ItemMap.keySet.iterator();
while(iter.hasNext()){
ListItem it = iter.next();
//...一些逻辑操作
iter.remove(it);
}
结果正确。
这个问题以前碰到过,但改好之后没分析原因,今天网上看了下,挺多解释的,转篇过来,以便查询,呵呵。
原来在Map或者Collection的时候,不要用它们的API直接修改集合的内容(否则会出现 java.util.ConcurrentModificationException 异常),如果要修改可以用Iterator的remove()方法。
转---
引用
原因分析:
当使用 fail-fast iterator 对 Collection 或 Map 进行迭代操作过程中尝试直接修改 Collection / Map 的内容时,即使是在单线程下运行, 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.
附:来自ibm developerworks上对java.util.concurrent包的说明片段:
java.util 包中的集合类都返回 fail-fast 迭代器,这意味着它们假设线程在集合内容中进行迭代时,集合不会更改它的内容。如果 fail-fast 迭代器检测到在迭代过程中进行了更改操作,那么它会抛出 ConcurrentModificationException ,这是不可控异常。
在迭代过程中不更改集合的要求通常会对许多并发应用程序造成不便。相反,比较好的是它允许并发修改并确保迭代器只要进行合理操作,就可以提供集合的一致视图,如 java.util.concurrent 集合类中的迭代器所做的那样。
java.util.concurrent 集合返回的迭代器称为弱一致的(weakly consistent) 迭代器。对于这些类,如果元素自从迭代开始已经删除,且尚未由 next() 方法返回,那么它将不返回到调用者。如果元素自迭代开始已经添加,那么它可能返回调用者,也可能不返回。在一次迭代中,无论如何更改底层集合,元素不会被返回两次。
分享到:
相关推荐
Java.util.ConcurrentModificationException 异常问题详解 ConcurrentModificationException 异常是 Java 中一个常见的异常,它发生在 Iterator 遍历集合时,集合同时被修改引起的异常。在 Java 中,集合类如 ...
java.util.ConcurrentModificationException 解决方法 在使用iterator.hasNext()操作迭代器的时候,如果此时迭代的对象发生改变,比如插入了新数据,或者有数据被删除。 则使用会报以下异常: Java.util....
### Java.util.Date与Java.sql.Date互转及字符串转换为日期时间格式 #### 一、Java.util.Date与Java.sql.Date的基本概念 在Java编程语言中,处理日期和时间时经常使用到`java.util.Date`和`java.sql.Date`这两个类...
### Java.util.Date与Java.sql.Date相互转换 #### 知识点概述 在Java开发中,经常需要处理日期和时间相关的操作。Java标准库提供了两个重要的日期类:`java.util.Date` 和 `java.sql.Date`。虽然它们名字相似,但...
### 使用 Java.util.zip 包实现数据压缩与解压 在计算机科学领域,数据压缩技术是一项重要的功能,它能够帮助减少存储空间的需求以及提高网络传输效率。本文将通过一系列的示例来详细介绍如何利用 Java 中的 `java....
在Java编程中,`java.util.ConcurrentModificationException` 是一个常见的运行时异常,通常发生在尝试并发修改集合时。这个异常的产生是由于集合类(如HashMap)的非线程安全特性,当你在一个线程中使用迭代器遍历...
1. java.util.concurrent - Java 并发工具包 2. 阻塞队列 BlockingQueue 3. 数组阻塞队列 ArrayBlockingQueue 4. 延迟队列 DelayQueue 5. 链阻塞队列 LinkedBlockingQueue 6. 具有优先级的阻塞队列 ...
在Java编程语言中,`java.util.InputMismatchException`是一个常见的运行时异常,它通常发生在尝试从数据源(如控制台、文件或数据库)读取数据时,遇到的数据类型与预期的不匹配。在这个特定的场景中,问题出在主线...
`java.util.concurrent.ExecutionException`通常是由于并发执行的Future或ExecutorService任务抛出异常导致的。在这个特定情况下,它伴随着`java.lang.OutOfMemoryError`,说明是内存不足引发了并发任务的执行失败。...
### Java.util.Date到JSON日期转换详解 在Java中处理日期并将其转换为JSON格式是常见的需求,尤其是在进行网络传输或存储操作时。本篇文章将详细介绍如何将`java.util.Date`对象转换为符合特定格式的JSON字符串,...
Java提供日期(Data)类、日历(Calendar)类,随机数(Random)类,堆栈(Stack)、向量(Vector) 、位集合(Bitset)以及哈希表(Hashtable)等类来表示相应的数据结构
### Java.util.logging.Logger 使用详解 #### 一、创建Logger对象 在Java中,`java.util.logging.Logger` 是标准的日志框架之一,它提供了基础的日志记录功能。为了使用这一功能,首先需要获得 `java.util.logging...
标题“java.util.pdf”暗示这是一个关于Java编程语言中util包的文档。由于描述和标签均重复标题,我们可以推断文档重点在于解释和示例展示java.util包中的类与接口。java.util是Java的标准库中的一个包,主要用于...
Java编程语言提供了两个重要的日期处理类,分别是`java.util.Date`和`java.sql.Date`,它们在处理日期和时间上有着不同的特性和用途。 `java.util.Date`是更通用的日期时间类,它包含了日期和时间的信息,可以精确...
Java.sql.Date与Java.util.Date的区别和转换 Java.util.Date和Java.sql.Date是Java中两种不同的日期和时间表示方式,虽然它们都是表示日期和时间,但是它们之间存在着一些重要的区别。 首先,Java.util.Date是Java...