java.util.ConcurrentModificationException 异常解决的方法及原理
近期在修程序的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 异常解决的方法及原理的更多相关文章
- java.util.ConcurrentModificationException异常原因及解决方法
在java语言中,ArrayList是一个很常用的类,在编程中经常要对ArrayList进行删除操作,在使用remove方法对ArrayList进行删除操作时,报java.util.Concurren ...
- java.util.ConcurrentModificationException异常的解决
问题复现: List<String> list = new ArrayList<>();list.add("11");list.add("55&q ...
- java.util.ConcurrentModificationException 异常问题详解
环境:JDK 1.8.0_111 在Java开发过程中,使用iterator遍历集合的同时对集合进行修改就会出现java.util.ConcurrentModificationException异常, ...
- java.util.ConcurrentModificationException异常分析
Java在操作ArrayList.HashMap.TreeMap等容器类时,遇到了java.util.ConcurrentModificationException异常.以ArrayList为例,如下 ...
- java.util.ConcurrentModificationException异常排查
java.util.ConcurrentModificationException对于这个异常我们一般会认为是在遍历list的时候对这个list做了add,remove等修改操作造成的,最近在线上 ...
- java集合--java.util.ConcurrentModificationException异常
ConcurrentModificationException 异常:并发修改异常,当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常.一个线程对collection集合迭代,另一个线程对Co ...
- Java处理java.util.ConcurrentModificationException异常
代码: public static void reduce(HashMap<String, Integer> hashMap, final Integer count) { Iterato ...
- java.util.ConcurrentModificationException的解决办法
今天在使用iterator.hasNext()操作迭代器的时候,当迭代的对象发生改变,比如插入了新数据,或者有数据被删除. 编译器报出了以下异常: Exception in thread " ...
- java.util.ConcurrentModificationException异常;java.util.ConcurrentModificationException实战
写代码遇到这个问题,很多博客文章都是在反复的强调理论,而没有对应的实例,所以这里从实例出发,后研究理论: 一.错误产生情况 1 .字符型 (1)添加 public static void main(S ...
随机推荐
- Android Stuido 好卡怎么办?不要急,兄弟来教你
近期使用Android studio 开发app,编译的时候特别卡,常常卡死.我的机器 i3 + 8G,按道理来说流畅的跑个androidstudio还是绰绰有余的... 于是在各大论坛寻找解决方式, ...
- vim-YCM插件安装
这两天开始使用vim来学习C++语言,中间少不了要进行编译.才刚刚写了两个小例子就开始发现,每次都要退出vim来进行编译,实在太麻烦了.这时候才想到之前有在一本关于vim的书籍上看到quickfix的 ...
- zzulioj--1775-- 和尚特烦恼1——是不是素数(素数水题)
1775: 和尚特烦恼1--是不是素数 Time Limit: 2 Sec Memory Limit: 128 MB Submit: 563 Solved: 193 SubmitStatusWeb ...
- java9新特性-21-java的动态编译器
1. 官方Feature 243: Java-Level JVM Compiler Interface 295: Ahead-of-Time Compilation 2. 产生背景 Oracle 一直 ...
- Android 学习笔记:Navigation Drawer
laylout文件: <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com ...
- solver及其配置
solver算是caffe的核心的核心,它协调着整个模型的运作.caffe程序运行必带的一个参数就是solver配置文件.运行代码一般为 # caffe train --solver=*_slover ...
- 排序算法(Apex 语言)
/* Code function : 冒泡排序算法 冒泡排序的优点:每进行一趟排序,就会少比较一次,因为每进行一趟排序都会找出一个较大值 时间复杂度:O(n*n) 空间复杂度:1 */ List< ...
- appium使用教程(一 环境搭建)-------------2.安装部署
1) 安装appium 2) SDK(不建议使用模拟器,占用内存很大,会造成机器卡顿.另外模拟器还存在兼容性问题:pc为x86架构,绝大多数的手机都是ARM架构,app的兼 ...
- iOS——集成支付宝 系统繁忙,请稍后再试ALI40247
问题描述:在调用支付宝时,老是显示,系统繁忙,请稍后再试ALI40247. 解决方案: 一.如何签约APP支付接口 第一步:进入管理中心:https://openhome.alipay.com/p ...
- Centos7(阿里云服务器)安装Anaconda的详细步骤与心得
在本地安装Anaconda的各个版本的文章已经很多,但是感觉不是很详细,因此,在此发发自己在Centos7(阿里云服务器)安装Anaconda的心得和步骤: 注:需要注意的地方会用不同颜色区别. 1. ...