HashMap vs ConcurrentHashMap — 示例及Iterator探秘
如果你是一名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
|
package com.journaldev.util;import java.util.HashMap;import java.util.Iterator;import java.util.Map;import java.util.concurrent.ConcurrentHashMap;public class ConcurrentHashMapExample { public static void main(String[] args) { //ConcurrentHashMap Map<String,String> myMap = new ConcurrentHashMap<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 = new HashMap<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}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.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)。 */transient volatile int modCount; |
现在为了证明上面的观点,我们对原来的代码做一点修改,使迭代器在插入新的元素后跳出循环。只要在调用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
[ 转载请保留原文出处、译者和译文链接。]
HashMap vs ConcurrentHashMap — 示例及Iterator探秘的更多相关文章
- 沉淀再出发:java中的HashMap、ConcurrentHashMap和Hashtable的认识
沉淀再出发:java中的HashMap.ConcurrentHashMap和Hashtable的认识 一.前言 很多知识在学习或者使用了之后总是会忘记的,但是如果把这些只是背后的原理理解了,并且记忆下 ...
- 轻松理解 Java HashMap 和 ConcurrentHashMap
前言 Map 这样的 Key Value 在软件开发中是非常经典的结构,常用于在内存中存放数据. 本篇主要想讨论 ConcurrentHashMap 这样一个并发容器,在正式开始之前我觉得有必要谈谈 ...
- 高并发第九弹:逃不掉的Map --> HashMap,TreeMap,ConcurrentHashMap
平时大家都会经常使用到 Map,面试的时候又经常会遇到问Map的,其中主要就是 ConcurrentHashMap,在说ConcurrentHashMap.我们还是先看一下, 其他两个基础的 Map ...
- 深入理解HashMap和concurrentHashMap
原文链接:https://segmentfault.com/a/1190000015726870 前言 Map 这样的 Key Value 在软件开发中是非常经典的结构,常用于在内存中存放数据. 本篇 ...
- HashMap与ConcurrentHashMap、HashTable
(1)HashMap的线程不安全原因一:死循环 原因在于HashMap在多线程情况下,执行resize()进行扩容时容易造成死循环. 扩容思路为它要创建一个大小为原来两倍的数组,保证新的容量仍为2的N ...
- JAVA HashMap与ConcurrentHashMap
HashMap Fast-Fail(遍历时写入操作异常) 在使用迭代器的过程中如果HashMap被修改,那么ConcurrentModificationException将被抛出,也即Fast-fai ...
- java并发编程笔记(十)——HashMap与ConcurrentHashMap
java并发编程笔记(十)--HashMap与ConcurrentHashMap HashMap参数 有两个参数影响他的性能 初始容量(默认为16) 加载因子(默认是0.75) HashMap寻址方式 ...
- JAVA学习:HashMap 和 ConcurrentHashMap
一.最基本的HashMap 和 ConcurrentHashMap 1.HashMap的结构和底层原理:由数组和链表组成,数组里面每个地方都存了Key-Value这样的实例,在Java7叫Entry ...
- HashMap?ConcurrentHashMap?
Java团长在csdn 2019-02-06 19:58:00 104241 收藏 666 来源:crossoverJie(ID:crossoverJie) 前言 Map 这样的 Key ...
随机推荐
- ListView 在设备切换横竖屏时保存状态
比如listview在设备切换横竖屏时,仍然需要保证position, activity - > onSaveInstanceState - > restoreInstanceState ...
- 邁向IT專家成功之路的三十則鐵律 鐵律二十九 IT人富足之道-信仰
天地自然的循環法則,讓每一個人都必須經歷生.老.病.死.喜.怒.哀.樂,然而至始至終無盡的煩惱總是遠多於快樂,因此筆者深信每一個人在一生當中,都必須要有適合自己的正確信仰,他可以在你無法以物質力量來解 ...
- 利用Thinkphp 5缓存漏洞实现前台Getshell
0×00 背景 网站为了实现加速访问,会将用户访问过的页面存入缓存来减小数据库查询的开销.而Thinkphp5框架的缓存漏洞使得在缓存中注入代码成为可能.(漏洞详情见参考资料) 本文将会详细讲解: 1 ...
- HDU 5289 Assignment(单调队列)
题意:给T足数据,然后每组一个n和k,表示n个数,k表示最大同意的能力差,接下来n个数表示n个人的能力,求能力差在k之内的区间有几个 分析:维护一个区间的最大值和最小值,使得他们的差小于k,于是採用单 ...
- 非常不错的ajax原理总结
在工作中用了Ajax N多次了,也看过一些相关方面的书籍,也算是认识了它,但是一直没有认真总结和整理过相关的东东,失败!近有闲情,将之总结如下:[名称]Ajax是Asynchronous JavaSc ...
- Atitit.ati  str  字符串增强api
Atitit.ati str 字符串增强api 1. java StringUtils方法全览 分类: Java2011-11-30 17:22 8194人阅读 评论(2) 收藏 举报 javas ...
- Cts框架解析(15)-任务运行完
case运行完成后.会回到CtsTest的run方法中: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaXRmb290YmFsbA==/font/5a6L ...
- Linux Setuid(SUID)和Setgid(SGID) sticky bit
http://www.php100.com/html/webkaifa/Linux/2010/0812/6392.html 1.setuid和setgid的解说 setuid和setgid位是让普通用 ...
- lockfile - conditional semaphore-file creator
LOCKFILE(1) LOCKFILE(1) NAME lockfile - conditional semaphore-file creator SYNOPSIS lockfile -sleept ...
- find and xargs
调整搜索深度 -mandepth 搜索当前目录,而不进入子目录: find . -maxdepth 0 -name "debug*" Linux中find常见用法示例 ·find ...