HashMap并发修改异常解决办法

本文介绍了在多线程环境下使用HashMap出现并发修改异常的原因及解决方案,推荐使用ConcurrentHashMap以提高程序的并发性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我在循环读取hashmap里的内容时,在循环中又在另外一个线程对hashmap进行修改,于是出现了如下这个异常

java.util.ConcurrentModificationException

翻译过来就是并发修改异常,上网找了下资料,解决方法如下:

调用HashMap的reomve方法时会出现 java.util.ConcurrentModificationException 。解决方法就是先用Iterator的方法remove,然后再调用HashMap的remove方法。即代码如下:

微笑

Iterator<Integer> keys = gradeMap.keySet().iterator();
while(keys.hasNext()) {
Integer i = keys.next();
i f(!gradesIds.contains(i)) {
keys.remove();
gradeMap.remove(i);

}

}

我加入这段代码之后,还是会出现该异常,于是继续寻找原因,发现了这样两段话:

1.如果你的程序是高并发,并且你的map是经常修改的,千万不要用HashMap,会把这个线常卡死的,要用ConcurrentHashMap


2.虽然HashTable和ConcurrentHashMap都是线程安全的,但是HashTable是同步容器,ConcurrentHashMap是并发容器,采用了锁分离策略,在并发环境中,应多使用ConcurrentHashMap,因为它具有非常好的并发性能,可以多个线程同时读写。而HashTable只能同时一个线程读写。
可以简单的把ConcurrentHashMap理解为多个HashMap组合,锁不是在ConcurrentHashMap上,而是在某个HashMap上。
注意:ConcurrentHashMap和HashMap的一个不同点就是ConcurrentHashMap里不能存放key和value为空的值。

于是我将Hashmap改为ConcurrentHashMap,经调试,解决了该问题。
### ConcurrentModificationException 异常的原因及解决方案 #### 异常原因 `java.util.ConcurrentModificationException` 是 Java 中的一种运行时异常,通常发生在使用迭代器(Iterator)遍历集合对象(如 `ArrayList`、`HashMap` 等)的过程中。当集合的结构被非迭代器自身的方法修改时(例如通过 `add` 或 `remove` 方法),就会抛出此异常[^2]。 这种异常的核心机制在于迭代器的 **fail-fast** 特性。在遍历过程中,迭代器会检查集合的修改计数器(`modCount`)是否与预期值(`expectedModCount`)一致。如果不一致,则说明集合在遍历过程中发生了结构上的修改,从而抛出 `ConcurrentModificationException`[^4]。 以下是异常检测源码的关键部分: ```java final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } ``` 上述代码展示了迭代器在每次调用 `next()` 方法时,都会执行 `checkForComodification()` 方法以确保集合未被并发修改。如果发现修改计数器不匹配,则立即抛出异常[^1]。 #### 解决方案 为避免 `ConcurrentModificationException`,可以采用以下几种方法: 1. **使用 Iterator 的 remove 方法** 在遍历集合时,应通过迭代器自身的 `remove()` 方法来移除元素,而不是直接调用集合的 `remove()` 方法。例如: ```java List<Integer> list = new ArrayList<>(); for (int i = 0; i < 10; i++) { list.add(i); } Iterator<Integer> iterator = list.iterator(); while (iterator.hasNext()) { Integer value = iterator.next(); if (value == 5) { iterator.remove(); // 使用迭代器的 remove 方法 } } ``` 2. **使用线程安全的集合类** 如果需要在多线程环境中操作集合,可以考虑使用线程安全的集合实现,例如 `CopyOnWriteArrayList` 或 `ConcurrentHashMap`。这些集合类通过内部机制保证了线程安全性,避免了 `ConcurrentModificationException` 的发生[^3]。 3. **使用同步块** 对于非线程安全的集合类,可以通过加锁的方式保护集合的访问和修改。例如: ```java List<Integer> list = Collections.synchronizedList(new ArrayList<>()); synchronized (list) { Iterator<Integer> iterator = list.iterator(); while (iterator.hasNext()) { Integer value = iterator.next(); if (value == 5) { iterator.remove(); } } } ``` 4. **避免在增强 for 循环中修改集合** 增强 for 循环本质上也是基于迭代器实现的,因此在循环体内直接调用集合的 `remove()` 方法会导致异常。例如以下代码会抛出异常: ```java List<Integer> list = new ArrayList<>(); for (int i = 0; i < 10; i++) { list.add(i); } for (Integer value : list) { // 增强 for 循环 if (value == 5) { list.remove(value); // 抛出 ConcurrentModificationException } } ``` 正确的做法是改用显式的迭代器进行操作。 #### 示例代码 以下是一个完整的示例,展示如何正确处理 `ConcurrentModificationException`: ```java import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class Main { public static void main(String[] args) { List<Integer> list = new ArrayList<>(); for (int i = 0; i < 10; i++) { list.add(i); } // 正确方式:使用 Iterator 的 remove 方法 Iterator<Integer> iterator = list.iterator(); while (iterator.hasNext()) { Integer value = iterator.next(); if (value == 5) { iterator.remove(); // 安全移除 } } System.out.println(list); // 输出结果:[0, 1, 2, 3, 4, 6, 7, 8, 9] } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值