转自http://hi.baidu.com/notyetfish/blog/item/aa744738393c26cad56225b4.html
在对一个map进行迭代遍历并删除一些符合条件的键值对的时候,容易出现
java.util.ConcurrentModificationException 这个异常。
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextEntry(HashMap.java:787)
at java.util.HashMap$KeyIterator.next(HashMap.java:823)
解决办法如下:
import java.util.*;
public class TestMap {
public TestMap() {
}
public static void main(String[] args) {
java.util.Map m = new java.util.HashMap();
m.put("aaa", "lizongbo ");
m.put("bbb", " lizongbo");
m.put("ccc", "lizongbo ");
m.put("ddd", " lizongbo");
m.put("eee", "lizongbo");
m.put("fff", "lizongbo");
m.put("ggg", "lizongbo");
m.put("adads", "lizongbo");
m.put("dffd", "lizongbo");
m.put("dcxv", "lizongbo");
m.put("lizongbo", "lizongbo");
m.put("ert", "lizongbo");
m.put("544", "lizongbo ");
Iterator iterator = m.keySet().iterator();
while (iterator.hasNext()) {
String sessionId = (String) iterator.next();
if ("ggg".equals(sessionId) || "lizongbo".equals(sessionId) ||
"544".equals(sessionId)) {
iterator.remove(); //这行代码是关键。
m.remove(sessionId);
}
}
System.out.println(m.get("ggg"));
System.out.println(m.get("lizongbo"));
System.out.println(m.get("544"));
}
当使用 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.
分享到:
相关推荐
在Java编程中,`java.util.ConcurrentModificationException` 是一个常见的运行时异常,通常发生在尝试并发修改集合时。这个异常的产生是由于集合类(如HashMap)的非线程安全特性,当你在一个线程中使用迭代器遍历...
`java.util.ConcurrentModificationException` 是一个在 Java 中常见的运行时异常,它通常发生在多线程环境中,当一个线程正在遍历一个集合(如 `ArrayList`, `HashMap` 等),而另一个线程同时尝试修改这个集合时。...
在这个例子中,当我们试图在遍历过程中删除一个元素时,迭代器会检测到Map的结构已被改变,从而抛出异常。这是因为迭代器在内部维护了一个指向集合的索引,当集合结构发生变化时,这个索引不再有效,导致迭代器无法...
但是,因为Vector是同步的,当一个Iterator被创建而且正在被使用,另一个线程改变了Vector的状态(例如,添加或删除元素),Iterator将抛出ConcurrentModificationException异常。 Set接口是Collection接口的子接口...
这段代码将抛出 `java.util.ConcurrentModificationException` 异常,因为在遍历 HashMap 的元素过程中删除了当前所在元素,下一个待访问的元素的指针也由此丢失了。 2. 正确的删除方法 正确的删除方法是使用迭代...
- `java.util.Iterator`的改进:支持`remove()`操作,避免抛出`ConcurrentModificationException`。 ### 4. 性能优化 JDK 1.6对编译器和垃圾收集器进行了优化,提高了运行效率,例如: - **Server VM的改进**: ...
- 故障安全迭代器,如 ConcurrentHashMap 的迭代器,即使在并发修改时也能安全地工作,不会抛出异常。 3. **Java BlockingQueue**: - Java BlockingQueue 是并发编程的重要工具,属于 `java.util.concurrent` 包...
即使知道某段代码可能抛出异常,也应该适当地捕获并处理,或者声明方法可能抛出的异常。 6. **资源管理不当**: 使用`FileInputStream`、`Socket`等需要手动关闭的资源时,忘记关闭可能会导致资源泄露。Java 7引入...
虽然在编译阶段可能没有问题,但在运行时,如果集合在迭代过程中被修改(添加、删除元素),可能会抛出`ConcurrentModificationException`。这是因为默认的迭代器不支持并发修改。为了安全地修改集合,可以使用`...
如果抛出一个异常,那么相匹配的 catch 子句就会执行,然后控制就会进入 finally 块(如果有的话)。 finalize?方法名。Java 技术允许使用 finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要的...
- 不要捕获并忽略异常,而应处理异常或向上抛出。 - 不要随便使用`Exception`作为捕获类型,应尽可能精确到具体异常。 - 使用`try-with-resources`语句处理需要关闭的资源。 5. **并发编程**: - 尽量避免使用`...
在遍历 `HashMap` 或其他集合时,如果修改容器(如添加、删除元素或更改元素),可能会抛出 `ConcurrentModificationException`。为了安全地修改容器,应使用 `Iterator` 或 `Map.Entry` 进行迭代。 4. 接口中定义...
java编译器要求方法必须声明抛出可能发生的非运行时异常,但是并不要求必须声明抛出未被捕获的运行时异常。 6、说出Servlet的生命周期,并说出Servlet和CGI的区别。 Servlet被服务器实例化后,容器运行其init方法,...
使用`Iterator`时,需特别注意并发修改异常`ConcurrentModificationException`,当在遍历过程中直接修改集合时,此异常会被抛出。而增强型`for`循环简化了遍历过程,适用于大部分情况,无需手动管理迭代器,同时也更...
java编译器要求方法必须声明抛出可能发生的非运行时异常,但是并不要求必须声明抛出未被捕获的运行时异常。 9、说出Servlet的生命周期,并说出Servlet和CGI的区别。 Servlet被服务器实例化后,容器运行其init方法...