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
转载请保留原文出处、译者和译文链接。]

时间: 2024-12-22 08:44:57

HashMap vs ConcurrentHashMap — 示例及Iterator探秘的相关文章

HashMap Hashtable ConcurrentHashMap 一点区别

HashMap  ConcurrentHashMap Hashtable 工作中经常会用到, HashMap用的最多, ConcurrentHashMap次之,hashTable用的最少. 简单看了下源码,其实原因还是挺明显的.从JDK的发展历程来看,hashTable是1.0就发布的,属于最早的key-value形式的存储, 到了1.2才有hashMap, ConcurrentHashMap是1.5中发布的,它们的实现有很多类同,也有很多细节上的区别.这里主要通过查看源码来比较下它们在写入与读

Java ConcurrentHashMap学习 —— HashMap Vs. ConcurrentHashMap Vs. SynchronizedMap – How a HashMap can be Synchronized in Java

HashMap is a very powerful data structure in Java. We use it everyday and almost in all applications. There are quite a few examples which I have written before on How to Implement Threadsafe cache, How to convert Hashmap to Arraylist? We used Hashma

深入理解HashMap、ConcurrentHashMap

前言 Map 这样的 Key Value 在软件开发中是非常经典的结构,常用于在内存中存放数据. 本篇主要想讨论 ConcurrentHashMap 这样一个并发容器,在正式开始之前我觉得有必要谈谈 HashMap,没有它就不会有后面的 ConcurrentHashMap. HashMap 众所周知 HashMap 底层是基于 数组 + 链表 组成的,不过在 jdk1.7 和 1.8 中具体实现稍有不同. Base 1.7 1.7 中的数据结构图: 先来看看 1.7 中的实现. 这是 HashM

深入剖析 Java7 中的 HashMap 和 ConcurrentHashMap

本文将深入剖析 Java7 中的 HashMap 和 ConcurrentHashMap 的源码,解析 HashMap 线程不安全的原理以及解决方案,最后以测试用例加以验证. 1 Java7 HashMap HashMap 的数据结构: 从上图中可以看出,HashMap 底层就是一个数组结构,数组中的每一项又是一个链表. 通过查看 JDK 中的 HashMap 源码,可以看到其构造函数有一行代码: public HashMap(int initialCapacity, float loadFac

高并发第九弹:逃不掉的Map --&gt; HashMap,TreeMap,ConcurrentHashMap

平时大家都会经常使用到 Map,面试的时候又经常会遇到问Map的,其中主要就是 ConcurrentHashMap,在说ConcurrentHashMap.我们还是先看一下, 其他两个基础的 Map 类: HashMap  和 TreeMap HashMap: public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable,Serializable { // 这里有个很逗

HashMap与ConcurrentHashMap、HashTable

(1)HashMap的线程不安全原因一:死循环 原因在于HashMap在多线程情况下,执行resize()进行扩容时容易造成死循环. 扩容思路为它要创建一个大小为原来两倍的数组,保证新的容量仍为2的N次方,从而保证上述寻址方式仍然适用.扩容后将原来的数组从新插入到新的数组中.这个过程称为reHash. [单线程下的reHash]  扩容前:我们的HashMap初始容量为2,加载因子为1,需要向其中存入3个key,分别为5.9.11,放入第三个元素11的时候就涉及到了扩容. 第一步:先创建一个二倍

JAVA学习:HashMap 和 ConcurrentHashMap

 一.最基本的HashMap 和 ConcurrentHashMap 1.HashMap的结构和底层原理:由数组和链表组成,数组里面每个地方都存了Key-Value这样的实例,在Java7叫Entry在Java8中叫Node 在JDK1.6,JDK1.7中,HashMap采用位桶+链表实现,即使用链表处理冲突,同一hash值的链表都存储在一个链表里.但是当位于一个桶中的元素较多,即hash值相等的元素较多时,通过key值依次查找的效率较低.而JDK1.8中,HashMap采用位桶+链表+红黑树实

Popular HashMap and ConcurrentHashMap Interview Questions

http://howtodoinjava.com/core-java/collections/popular-hashmap-and-concurrenthashmap-interview-questions/ Popular HashMap and ConcurrentHashMap Interview Questions June 14, 2013 by Lokesh Gupta In my previous post related to “How HashMap works in jav

[Java集合] 彻底搞懂HashMap,HashTable,ConcurrentHashMap之关联.

注: 今天看到的一篇讲hashMap,hashTable,concurrentHashMap很透彻的一篇文章, 感谢原作者的分享. 原文地址: http://blog.csdn.net/zhangerqing/article/details/8193118 Java集合类是个非常重要的知识点,HashMap.HashTable.ConcurrentHashMap等算是集合类中的重点,可谓"重中之重",首先来看个问题,如面试官问你:HashMap和HashTable有什么区别,一个比较简