`
llyzq
  • 浏览: 585323 次
  • 性别: 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的改进**: ...

    13.foreach循环_java_

    如果尝试这样做,编译器会抛出错误。例如,试图在循环中改变数组或集合的元素会报错。 4. **无法跳过元素或提前退出**: 由于`foreach`循环的底层实现,你不能使用`break`或`continue`语句来跳过当前元素或提前...

    java-collection-all-in-one.pdf

    fail-fast迭代器在检测到集合结构被修改的情况下会快速抛出ConcurrentModificationException异常;fail-safe迭代器则不会抛出这种异常,因为它工作在集合的复制之上,如使用CopyOnWriteArrayList。迭代List集合的...

    Java 10道中级面试题.docx

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

    集合框架面试题.pdf

    而java.util.concurrent包下的集合类则提供安全失败迭代器,它们在遍历时不会因为集合被修改而抛出异常,因为它们是基于集合的快照来实现的。 4. HashMap是一个用于存储键值对的集合。它基于哈希表的Map接口实现,...

    java-大数据基础面试思考.pdf

    快速失败(Fail-Fast)迭代器机制是指在用迭代器遍历集合的过程中,如果检测到集合在迭代过程中被修改了,就会迅速抛出ConcurrentModificationException异常。快速失败机制的迭代器是为单线程设计的,因为它们不能...

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

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

    java基础 集合-22-迭代器设计模式

    5. **遍历Map的迭代器** 对于Map,我们不能直接使用迭代器遍历键值对,但可以分别获取键集(keySet)和值集(values)的迭代器。或者使用`entrySet()`方法获取Entry迭代器,每个Entry包含键值对。 6. **并发迭代**...

    高级程序员必会的HashMap的线程安全问题,适用于0~2年的.7z

    由于HashMap不是线程安全的,一个线程在遍历HashMap的同时,另一个线程对HashMap进行修改(如添加、删除元素),会导致迭代器失效,从而抛出异常。 2. **数据不一致**:由于HashMap的内部实现,如resize操作,可能...

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

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

    集合类编程题(2),使用迭代器(2).zip

    迭代器的使用遵循“fail-fast”原则,即如果在迭代过程中修改了集合,迭代器会抛出`ConcurrentModificationException`。 现在,让我们分析给定的文件`First.java`和`Student.java`。假设`First.java`是主程序,它...

    阿里巴巴Java开发代码规约

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

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

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

    阿里开发规范(集合与并发处理)

    **强制规定**:在 JDK7 及以上版本中,`Comparator` 实现类需要满足以下三个条件,否则在使用 `Arrays.sort` 或 `Collections.sort` 时会抛出 `IllegalArgumentException` 异常。 - **条件一**:`x` 和 `y` 的比较...

Global site tag (gtag.js) - Google Analytics