2019独角兽企业重金招聘Python工程师标准>>>

如果你是一名Java开发人员,我能够确定你肯定知道ConcurrentModificationException,它是在使用迭代器遍历集合对象时修改集合对象造成的(并发修改)异常。实际上,Java的集合框架是迭代器设计模式的一个很好的实现。

Java 1.5引入了java.util.concurrent包,其中Collection类的实现允许在运行过程中修改集合对象。

ConcurrentHashMap是一个与HashMap很相似的类,但是它支持在运行时修改集合对象。

让我们通过一个简单的程序来帮助理解:

ConcurrentHashMapExample.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
packagecom.journaldev.util;
importjava.util.HashMap;
importjava.util.Iterator;
importjava.util.Map;
importjava.util.concurrent.ConcurrentHashMap;
publicclassConcurrentHashMapExample {
publicstaticvoidmain(String[] args) {
//ConcurrentHashMap
Map<String,String> myMap =newConcurrentHashMap<String,String>();
myMap.put("1","1");
myMap.put("2","1");
myMap.put("3","1");
myMap.put("4","1");
myMap.put("5","1");
myMap.put("6","1");
System.out.println("ConcurrentHashMap before iterator: "+myMap);
Iterator<String> it = myMap.keySet().iterator();
while(it.hasNext()){
String key = it.next();
if(key.equals("3")) myMap.put(key+"new","new3");
}
System.out.println("ConcurrentHashMap after iterator: "+myMap);
//HashMap
myMap =newHashMap<String,String>();
myMap.put("1","1");
myMap.put("2","1");
myMap.put("3","1");
myMap.put("4","1");
myMap.put("5","1");
myMap.put("6","1");
System.out.println("HashMap before iterator: "+myMap);
Iterator<String> it1 = myMap.keySet().iterator();
while(it1.hasNext()){
String key = it1.next();
if(key.equals("3")) myMap.put(key+"new","new3");
}
System.out.println("HashMap after iterator: "+myMap);
}
}

当我们试着运行上面的程序,输出如下:

1
2
3
4
5
6
7
ConcurrentHashMap before iterator: {1=1, 5=1, 6=1, 3=1, 4=1, 2=1}
ConcurrentHashMap after iterator: {1=1, 3new=new3, 5=1, 6=1, 3=1, 4=1, 2=1}
HashMap before iterator: {3=1, 2=1, 1=1, 6=1, 5=1, 4=1}
Exceptioninthread"main"java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextEntry(HashMap.java:793)
at java.util.HashMap$KeyIterator.next(HashMap.java:828)
at com.test.ConcurrentHashMapExample.main(ConcurrentHashMapExample.java:44)

查看输出,很明显ConcurrentHashMap可以支持向map中添加新元素,而HashMap则抛出了ConcurrentModificationException。

查看异常堆栈记录,可以发现是下面这条语句抛出异常:

1
String key = it1.next();

这就意味着新的元素在HashMap中已经插入了,但是在迭代器执行时出现错误。事实上,集合对象的迭代器提供快速失败(Fail-Fast)的机制,即修改集合对象结构或者元素数量都会使迭代器触发这个异常。

但是迭代器是怎么知道HashMap被修改了呢,我们可以一次取出HashMap的所有Key然后进行遍历。

HashMap包含一个修改计数器,当你调用它的next()方法来获取下一个元素时,迭代器将会用到这个计数器。

HashMap.java

1
2
3
4
5
6
7
/**
* HashMap结构的修改次数
* 结构修改是指:改变了HashMap中mapping的个数或者其中的内部结构(比如,重新计算hash值)
* 这个字段在通过Collection操作Hashmap时提供快速失败(Fail-fast)功能。
* (参见 ConcurrentModificationException)。
*/
transientvolatileintmodCount;

现在为了证明上面的观点,我们对原来的代码做一点修改,使迭代器在插入新的元素后跳出循环。只要在调用put方法后增加一个break:

1
2
3
4
if(key.equals("3")){
myMap.put(key+"new","new3");
break;
}

再执行修改后的代码,会得到下面的输出结果:

1
2
3
4
ConcurrentHashMap before iterator: {1=1, 5=1, 6=1, 3=1, 4=1, 2=1}
ConcurrentHashMap after iterator: {1=1, 3new=new3, 5=1, 6=1, 3=1, 4=1, 2=1}
HashMap before iterator: {3=1, 2=1, 1=1, 6=1, 5=1, 4=1}
HashMap after iterator: {3=1, 2=1, 1=1, 3new=new3, 6=1, 5=1, 4=1}

最后,如果我们不添加新的元素而是修改已经存在的键值对会不会抛出异常呢?

修改原来的程序并且自己验证一下:

1
2
//myMap.put(key+"new", "new3");
myMap.put(key,"new3");

如果你对于输出结果感觉困惑或者震惊,在下面评论。我会很乐意给出进一步解释。

你有没有注意到那些我们在创建集合和迭代器时的尖括号,在Java中这叫做泛型,当涉及到编译时的类型检查和去除运行时的ClassCastException的时候会很有帮助。点击这里可以了解更多泛型教程。

原文链接:  journaldev  翻译:  ImportNew.com  -  风恋星
译文链接:  http://www.importnew.com/8162.html
转载请保留原文出处、译者和译文链接。 ]

转载于:https://my.oschina.net/u/165124/blog/373724

HashMap vs ConcurrentHashMap — 示例及Iterator探秘相关推荐

  1. Java 7:HashMap与ConcurrentHashMap

    从我过去有关性能的文章和HashMap案例研究中可能已经看到,Java线程安全性问题可以很轻松地使Java EE应用程序和Java EE容器崩溃. 在对Java EE性能问题进行故障排除时,我观察到的 ...

  2. java+线程安全的hash,多线程下HashMap安全问题-ConcurrentHashMap解析

    Java1.5 引入了 java.util.concurrent 包,其中 Collection 类的实现允许在运行过程中修改集合对象.实际上, Java 的集合框架是[迭代器设计模式]的一个很好的实 ...

  3. Hashtable,HashMap,ConcurrentHashMap都是Map的实现类,它们在处理null值的存储上有细微的区别,下列哪些说法是正确的

    多选 Hashtable,HashMap,ConcurrentHashMap都是Map的实现类,它们在处理null值的存储上有细微的区别,下列哪些说法是正确的:答案在文末 A. Hashtable的K ...

  4. Java7/8 中的 HashMap 和 ConcurrentHashMap

    Java7 HashMap  数组+链表 Java7 ConcurrentHashMap   Segment数组+HashEntry数组链表+ReenTrantLock分段锁 Java8 HashMa ...

  5. HashMap与ConcurrentHashMap的测试报告

    日期:2008-9-10 测试平台: CPU:Intel Pentium(R) 4 CPU 3.06G 内存:4G 操作系统:window server 2003 一.HashMap与Concurre ...

  6. HashMap、ConcurrentHashMap原理分析

    集合(Collection)是编程中常用的数据结构,而并发也是服务器端编程常用的技术之一,并发总是离不开集合这类高级数据结构的支持.比如两个线程需要同时访问一个中间临界区(Queue),比如常会用缓存 ...

  7. HashMap与ConcurrentHashMap万字源码分析

    HashMap与ConcurrentHashMap`源码解析 JDK版本:1.7 & 1.8 ​ 开发中常见的数据结构有三种: 1.数组结构:存储区间连续.内存占用严重.空间复杂度大 优点:因 ...

  8. Java之HashMap系列--ConcurrentHashMap的原理

    原文网址:Java之HashMap系列--ConcurrentHashMap的原理_IT利刃出鞘的博客-CSDN博客 简介 本文介绍Java中的ConcurrentHashMap的原理. JDK7与J ...

  9. Java Collection系列之HashMap、ConcurrentHashMap、LinkedHashMap的使用及源码分析

    文章目录 HashMap HashMap的存储结构 初始化 put & get put元素 get元素 扩容 遍历Map jdk1.8中的优化 ConcurrentHashMap jdk1.7 ...

最新文章

  1. 嵌入式系统中时间的应用以及rtc的验证过程
  2. 如何具备无坚不摧的意志力
  3. 算法题目中常见的几种输入小点-gets,cin,scanf,getline,sstream
  4. leetcode 477. 汉明距离总和(位运算)
  5. 如何造一个“钉钉”?谈谈消息系统架构的实现
  6. curl有php内存缓存,PHP CURL内存泄露的解决方法
  7. eclipse 使用 maven 无法编译 jsp 文件的问题
  8. (原创) cocos2d-x 3.0+ lua 学习和工作(4) : 公共函数(8): 生成只读table
  9. TabActivity,LocalActivityManager,TabHost,TabWidget深度分析(二)
  10. 广义线性模型(GLM, Generalized Linear Model)
  11. word标题在大纲视图下统一升降级
  12. 员工符合签订无固定期限劳动合同的条件,这种情况单位有权不予续签吗?
  13. mysql execute 方法_MyEclipse------execute()使用方法
  14. Android 获取定位权限,获取位置信息(国家、地区、经纬)
  15. 如何快速清洗空调扇(水冷式电风扇)(图文教程)
  16. 【IoT】产品设计之结构设计:3D打印表面处理之喷油
  17. python解析pdf,读取文字,可识别两栏pdf等
  18. 深入讲解破解Excel Vba工程密码
  19. Webservice简介
  20. 网易工程师亲历:一次sql缺少where条件的惨案…

热门文章

  1. c++基础学习(05)--(指针,引用)
  2. window电脑查看ssh公钥,以及将自己的公钥添加到Github等类似网站
  3. ffmpeg-0.6.3 移植到 windows 开源代码
  4. FFMpeg分析详细分析
  5. Springboot Mybatis 整合(完整版)
  6. Cron表达式、定时任务
  7. Equation漏洞混淆利用分析总结(下)
  8. webrtc 源码结构
  9. 浅析Numpy.genfromtxt及File I/O讲解
  10. A* a=new B ,会不会产生内存泄露了,露了B-A的部分?