`
llyzq
  • 浏览: 579805 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

遍历Map时抛出java.util.ConcurrentModificationException异常的解决办法

    博客分类:
  • J2SE
 
阅读更多
转自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.util.ConcurrentModificationException 问题及解决办法

    在Java编程中,`java.util.ConcurrentModificationException` 是一个常见的运行时异常,通常发生在尝试并发修改集合时。这个异常的产生是由于集合类(如HashMap)的非线程安全特性,当你在一个线程中使用迭代器遍历...

    java.util.ConcurrentModificationException 解决方法

    `java.util.ConcurrentModificationException` 是一个在 Java 中常见的运行时异常,它通常发生在多线程环境中,当一个线程正在遍历一个集合(如 `ArrayList`, `HashMap` 等),而另一个线程同时尝试修改这个集合时。...

    java 集合并发操作出现的异常ConcurrentModificationException

    在这个例子中,当我们试图在遍历过程中删除一个元素时,迭代器会检测到Map的结构已被改变,从而抛出异常。这是因为迭代器在内部维护了一个指向集合的索引,当集合结构发生变化时,这个索引不再有效,导致迭代器无法...

    Java语言的Util类详细介绍

    但是,因为Vector是同步的,当一个Iterator被创建而且正在被使用,另一个线程改变了Vector的状态(例如,添加或删除元素),Iterator将抛出ConcurrentModificationException异常。 Set接口是Collection接口的子接口...

    Java HashMap 如何正确遍历并删除元素的方法小结

    这段代码将抛出 `java.util.ConcurrentModificationException` 异常,因为在遍历 HashMap 的元素过程中删除了当前所在元素,下一个待访问的元素的指针也由此丢失了。 2. 正确的删除方法 正确的删除方法是使用迭代...

    jdk 1.6 API 中文版帮助文档

    - `java.util.Iterator`的改进:支持`remove()`操作,避免抛出`ConcurrentModificationException`。 ### 4. 性能优化 JDK 1.6对编译器和垃圾收集器进行了优化,提高了运行效率,例如: - **Server VM的改进**: ...

    Java 10道中级面试题.docx

    - 故障安全迭代器,如 ConcurrentHashMap 的迭代器,即使在并发修改时也能安全地工作,不会抛出异常。 3. **Java BlockingQueue**: - Java BlockingQueue 是并发编程的重要工具,属于 `java.util.concurrent` 包...

    Java程序员们最常犯的10个错误.docx

    即使知道某段代码可能抛出异常,也应该适当地捕获并处理,或者声明方法可能抛出的异常。 6. **资源管理不当**: 使用`FileInputStream`、`Socket`等需要手动关闭的资源时,忘记关闭可能会导致资源泄露。Java 7引入...

    关于方法iterator()找不着的问题~~~~~

    虽然在编译阶段可能没有问题,但在运行时,如果集合在迭代过程中被修改(添加、删除元素),可能会抛出`ConcurrentModificationException`。这是因为默认的迭代器不支持并发修改。为了安全地修改集合,可以使用`...

    JAVA面试题最全集

    如果抛出一个异常,那么相匹配的 catch 子句就会执行,然后控制就会进入 finally 块(如果有的话)。 finalize?方法名。Java 技术允许使用 finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要的...

    阿里巴巴Java开发代码规约

    - 不要捕获并忽略异常,而应处理异常或向上抛出。 - 不要随便使用`Exception`作为捕获类型,应尽可能精确到具体异常。 - 使用`try-with-resources`语句处理需要关闭的资源。 5. **并发编程**: - 尽量避免使用`...

    进入华为必备的面试题(5.12)

    在遍历 `HashMap` 或其他集合时,如果修改容器(如添加、删除元素或更改元素),可能会抛出 `ConcurrentModificationException`。为了安全地修改容器,应使用 `Iterator` 或 `Map.Entry` 进行迭代。 4. 接口中定义...

    java 面试题 总结

    java编译器要求方法必须声明抛出可能发生的非运行时异常,但是并不要求必须声明抛出未被捕获的运行时异常。 6、说出Servlet的生命周期,并说出Servlet和CGI的区别。 Servlet被服务器实例化后,容器运行其init方法,...

    关于Java集合框架的总结

    使用`Iterator`时,需特别注意并发修改异常`ConcurrentModificationException`,当在遍历过程中直接修改集合时,此异常会被抛出。而增强型`for`循环简化了遍历过程,适用于大部分情况,无需手动管理迭代器,同时也更...

    超级有影响力霸气的Java面试题大全文档

    java编译器要求方法必须声明抛出可能发生的非运行时异常,但是并不要求必须声明抛出未被捕获的运行时异常。 9、说出Servlet的生命周期,并说出Servlet和CGI的区别。  Servlet被服务器实例化后,容器运行其init方法...

Global site tag (gtag.js) - Google Analytics