HashMap之java.util.ConcurrentModificationException问题原因及解决办法

两盒软妹~` 提交于 2020-02-05 06:00:21
Map<Warn,Object> map = new HashMap<>();

for(Entry<Warn,Object> entry : map.entrySet()){
    ...
    ...
    map.remove(entry.getKey());
    ...
}

报错:java.util.ConcurrentModificationException异常。

后经查询,在进行迭代时,同时对其进行remove().操作会影响迭代。原因在于: 迭代器的modCount和expectedModCount的值不一致.

没有源码照片了。如果remove()后源码会判断值不一致,然后在hashMap中抛出java.util.ConcurrentModificationException异常.

这个问题需要了解一点:HashMap不是线程安全的,ConcurrentHashMap是线程安全的。

因此,解决这个问题就有一个了简单粗暴的方法,使用ConcurrentHashMap代替HashMap。亲测可用。

另外,还有一个方法,在修改HashMap的上下文进行加锁操作。但是效率太差或者占用内存太高。ConcurrentHashMap效率感觉快赶上不同步的速度。推荐。

List和Map等集合类都存在上述问题,还请注意

 

--------------------

以下为补充内容。方便以后学习。为转载文章。

Java在操作ArrayList、HashMap、TreeMap等容器类时,遇到了java.util.ConcurrentModificationException异常。以ArrayList为例,如下面的代码片段:

package sqlMap;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Test {
	public static void main(String[] args) {
		List<String> strList = new ArrayList<String>();
		strList.add("string1");
		strList.add("string2");
		strList.add("string3");
		strList.add("string4");
		strList.add("string5");
		strList.add("string6");
		// 操作方式1:while(Iterator);报错
		Iterator<String> it = strList.iterator();
		while (it.hasNext()) {
			String s = it.next();
			if ("string2".equals(s)) {
				strList.remove(s);
			}
		}
		// 解决方案1:使用Iterator的remove方法删除元素
		// 操作方式1:while(Iterator):不报错
		// Iterator<String> it = strList.iterator();
		// while(it.hasNext()) {
		// String s = it.next();
		// if("string2".equals(s)) {
		// it.remove();
		// }
		// }
		// 操作方式2:foreach(Iterator);报错
		// for(String s : strList) {
		// if("string2".equals(s)) {
		// strList.remove(s);
		// }
		// }
		// 解决方案2:不使用Iterator遍历,注意索引的一致性
		// 操作方式3:for(非Iterator);不报错;注意修改索引
		// for(int i=0; i<strList.size(); i++) {
		// String s = strList.get(i);
		// if("string2".equals(s)) {
		// strList.remove(s);
		// strList.remove(i);
		// i--;
		// 元素位置发生变化,修改i
		// }
		// }
		// 解决方案3:新建一个临时列表,暂存要删除的元素,最后一起删除
		// List<String> templist = new ArrayList<String>();
		// for (String s : strList) {
		// if(s.equals("string2")) {
		// templist.add(s);
		// }
		// }
		//
		// 查看removeAll源码,其使用Iterator进行遍历
		// strList.removeAll(templist);
		// 解决方案4:使用线程安全CopyOnWriteArrayList进行删除操作
		// List<String> strList = new CopyOnWriteArrayList<String>();
		// strList.add("string1");
		// strList.add("string2");
		// strList.add("string3");
		// strList.add("string4");
		// strList.add("string5");
		// strList.add("string6");
		// Iterator<String> it = strList.iterator();
		// while (it.hasNext()) {
		// String s = it.next();
		// if (s.equals("string2")) {
		// strList.remove(s);
		// }
		// } } }
	}
}

执行上述代码后,报错如下:

Exception in thread "main" java.util.ConcurrentModificationException
	at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
	at java.util.ArrayList$Itr.next(Unknown Source)
	at concurrentModificationException.Test.main(Test.java:21)

在第21行报错,即it.next(),迭代器在获取下一个元素时报错。找到java.util.ArrayList第830行,看到it.next()的源代码,如下:

@SuppressWarnings("unchecked")        
public E next() {            
	checkForComodification();            
	int i = cursor;            
	if (i >= size)                
		throw new NoSuchElementException();            
	Object[] elementData = ArrayList.this.elementData;            
	if (i >= elementData.length)                
		throw new ConcurrentModificationException();            
	cursor = i + 1;            
	return (E) elementData[lastRet = i];       
}

调用了checkForComodification()方法,代码如下:

final void checkForComodification() {            
    if (modCount != expectedModCount)                
    throw new ConcurrentModificationException();        
}

以上部分内容为转载内容。原文链接:https://blog.csdn.net/kingzone_2008/article/details/41368989

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!