近期在修程序的bug,发现后台抛出下面异常:

Exception in thread "main" java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextEntry(HashMap.java:793)
at java.util.HashMap$KeyIterator.next(HashMap.java:828)
at com.keyman.demo.test.ClearResultTable.method2(ClearResultTable.java:54)
at com.keyman.demo.test.ClearResultTable.main(ClearResultTable.java:88)

找到报错行:at com.keyman.demo.test.ClearResultTable.method2(ClearResultTable.java:54)发现,报错位置:for (String s1 : sets)

		Set<String> sets = map.keySet();
for (String s1 : sets) {
String value = map.get(s1);
// 删除满足value以abc开头的键值对
if (value.startsWith("abc")) {
map.remove(s1);
}
}

或者以下的方式相同也会抛出异常

		Iterator<String> iterator = map.keySet().iterator();
while (iterator.hasNext()) {
String key = iterator.next();
String value = map.get(key);
// 删除满足value以abc开头的键值对
if (value.startsWith("abc")) {
map.remove(key);
//iterator.remove(); // 同步modCount和expectedModCount }
}

事实上无论是Map还是Set这样操作时均会抛出此异常!

解决的方法为:假设不是Iterator迭代方式,则改动map迭代方式为Iterator()方式。採用iterator.remove();而不直接通过map.remove();

                Iterator<String> iterator = map.keySet().iterator();
while (iterator.hasNext()) {
String key = iterator.next();
String value = map.get(key);
// 删除满足value以abc开头的键值对
if (value.startsWith("abc")) {
//map.remove(value);
iterator.remove(); // 关键代码,同步modCount和expectedModCount }
}

具体原因例如以下:

发现这个位置应该是不会报错的。查找前后文,发现最有可能报错的应该是for循环里面,可是咋一看压根没错!通过查找资料发现:当改动的个数跟期望改动的个数不相等时抛出此异常。

        private abstract class HashIterator<E> implements Iterator<E> {
Entry<K, V> next; // next entry to return
int expectedModCount; // For fast-fail
int index; // current slot
Entry<K, V> current; // current entry
...
final Entry<K, V> nextEntry() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException(); // 抛出异常
Entry<K, V> e = current = next;
if (e == null)
throw new NoSuchElementException(); if ((next = e.next) == null) {
Entry[] t = table;
while (index < t.length && (next = t[index++]) == null)
;
}
return e;
}
...
}

于是查看HashMap.remove()方法代码例如以下:

    /**
* Removes the mapping for the specified key from this map if present.
*
* @param key key whose mapping is to be removed from the map
* @return the previous value associated with <tt>key</tt>, or
* <tt>null</tt> if there was no mapping for <tt>key</tt>.
* (A <tt>null</tt> return can also indicate that the map
* previously associated <tt>null</tt> with <tt>key</tt>.)
*/
public V remove(Object key) {
Entry<K,V> e = removeEntryForKey(key);
return (e == null ? null : e.value);
} /**
* Removes and returns the entry associated with the specified key
* in the HashMap. Returns null if the HashMap contains no mapping
* for this key.
*/
final Entry<K,V> removeEntryForKey(Object key) {
int hash = (key == null) ? 0 : hash(key.hashCode());
int i = indexFor(hash, table.length);
Entry<K,V> prev = table[i];
Entry<K,V> e = prev; while (e != null) {
Entry<K,V> next = e.next;
Object k;
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k)))) {
modCount++;
size--;
if (prev == e)
table[i] = next;
else
prev.next = next;
e.recordRemoval(this);
return e;
}
prev = e;
e = next;
} return e;
}

你会发现,当中有modCount++操作。modCount表示改动的次数。而并没有改变其exceptedmodCount;

接下来看看iterator.remove()方法:(java.util.Hashtable.Enumerator.remove())

	public void remove() {
if (!iterator)
throw new UnsupportedOperationException();
if (lastReturned == null)
throw new IllegalStateException("Hashtable Enumerator");
if (modCount != expectedModCount)
throw new ConcurrentModificationException(); synchronized(Hashtable.this) {
Entry[] tab = Hashtable.this.table;
int index = (lastReturned.hash & 0x7FFFFFFF) % tab.length; for (Entry<K,V> e = tab[index], prev = null; e != null;
prev = e, e = e.next) {
if (e == lastReturned) {
modCount++;
expectedModCount++;
if (prev == null)
tab[index] = e.next;
else
prev.next = e.next;
count--;
lastReturned = null;
return;
}
}
throw new ConcurrentModificationException();
}
}
}

而此删除元素的方法,将modCount自增的同一时候将exceptedModCount相同自增。也就不会抛出异常。

java.util.ConcurrentModificationException 异常解决的方法及原理的更多相关文章

  1. java.util.ConcurrentModificationException异常原因及解决方法

    在java语言中,ArrayList是一个很常用的类,在编程中经常要对ArrayList进行删除操作,在使用remove方法对ArrayList进行删除操作时,报java.util.Concurren ...

  2. java.util.ConcurrentModificationException异常的解决

    问题复现: List<String> list = new ArrayList<>();list.add("11");list.add("55&q ...

  3. java.util.ConcurrentModificationException 异常问题详解

    环境:JDK 1.8.0_111 在Java开发过程中,使用iterator遍历集合的同时对集合进行修改就会出现java.util.ConcurrentModificationException异常, ...

  4. java.util.ConcurrentModificationException异常分析

    Java在操作ArrayList.HashMap.TreeMap等容器类时,遇到了java.util.ConcurrentModificationException异常.以ArrayList为例,如下 ...

  5. java.util.ConcurrentModificationException异常排查

      java.util.ConcurrentModificationException对于这个异常我们一般会认为是在遍历list的时候对这个list做了add,remove等修改操作造成的,最近在线上 ...

  6. java集合--java.util.ConcurrentModificationException异常

    ConcurrentModificationException 异常:并发修改异常,当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常.一个线程对collection集合迭代,另一个线程对Co ...

  7. Java处理java.util.ConcurrentModificationException异常

    代码: public static void reduce(HashMap<String, Integer> hashMap, final Integer count) { Iterato ...

  8. java.util.ConcurrentModificationException的解决办法

    今天在使用iterator.hasNext()操作迭代器的时候,当迭代的对象发生改变,比如插入了新数据,或者有数据被删除. 编译器报出了以下异常: Exception in thread " ...

  9. java.util.ConcurrentModificationException异常;java.util.ConcurrentModificationException实战

    写代码遇到这个问题,很多博客文章都是在反复的强调理论,而没有对应的实例,所以这里从实例出发,后研究理论: 一.错误产生情况 1 .字符型 (1)添加 public static void main(S ...

随机推荐

  1. RISC-V首度被我国列入扶持对象,上海已成RISC-V重要“据点”

    时间:2018年7月24日 16:33 摘要:近期,上海市经济信息委发布了<上海市经济信息化委关于开展2018年度第二批上海市软件和集成电路产业发展专项资金(集成电路和电子信息制造领域)项目申报 ...

  2. springboot shiro配置

    导入相关包(这里配合使用Ehcache缓存) <dependency> <groupId>org.apache.shiro</groupId> <artifa ...

  3. Everedit软件下载、安装和运行(免注册)

    不多说,最近,无意中,留意到这款软件.  前言 1.这是免注册版本   (推荐,这个是别人开发做出来的,放心!) 2.这是需注册版本    (这个是去官网) EverEdit是专门为国人设计的一流文本 ...

  4. hive查询不加分区的一个异常

    今天下午有同事反馈她提交了了一个SQL后,hive 查询就停止响应了. 我看了下,发现hiveserver确实hug住了.听过查看日志,发现了一个牛逼的SQL, 这个SQL很简单: select a. ...

  5. [转]60fps on the mobile web

    Flipboard launched during the dawn of the smartphone and tablet as a mobile-first experience, allowi ...

  6. JavaScript,ES5和ES6的区别

    什么是JavaScript JavaScript一种动态类型.弱类型.基于原型的客户端脚本语言,用来给HTML网页增加动态功能.(好吧,概念什么最讨厌了) 动态: 在运行时确定数据类型.变量使用之前不 ...

  7. linux 常用文本操作相关命令

    平时工作经常会对文本进行相关操作,包括读写.替换.统计等等,借此整理和学习一下有关命令. 1. cat 查看文件中的内容, -n 查看时为每一行加编号; -b 和-n类似,只不过对于空白行不编号: 2 ...

  8. hdu 5412 CRB and Queries(整体二分)

    题意 动态区间第k大 (n<=100000,m<=100000) 题解 整体二分的应用. 与静态相比差别不是很大.(和CDQ还有点像)所以直接上代码. #include<iostre ...

  9. echarts 绑定事件重复执行问题。

    网上所有,先调用.off 方法后再调用.on 绑定事件. 无效果,查看api未发现off方法,于是采用,先删除原先元素,后重新生成的方式. 场景描述. 用户查询时,每次结果都对应一张饼图.该张饼图绑定 ...

  10. minixml的安装教程

    最近想要实现对xml的解析,上网看到有很多库可以直接调用,例如minixml,tinyxml等,我选择了minixml(没有原因,纯属是因为这个找到了中文文档- -) 附上中文文档链接:https:/ ...