SynchronizedMap和ConcurrentHashMap的深入分析

在开始之前,先介绍下Map是什么?

javadoc中对Map的解释如下:

An objectthat maps keys to values . Amap cannot contain duplicatekeys; each key can map to at most one value.

This interface takes the place of the Dictionary class, which was atotally abstract class rather than an interface.

The Map interface provides three collection views, which allow amap's contents to be viewed as a set of keys, collection of values,or set of key-value mappings.

从上可知,Map用于存储“key-value”元素对,它将一个key映射到一个而且只能是唯一的一个value。

Map可以使用多种实现方式,HashMap的实现采用的是hash表;而TreeMap采用的是红黑树。

1. Hashtable 和 HashMap

这两个类主要有以下几方面的不同:

Hashtable和HashMap都实现了Map接口,但是Hashtable的实现是基于Dictionary抽象类。

在HashMap中,null可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null。当get()方法返回null值时,即可以表示HashMap中没有该键,也可以表示该键所对应的值为null。因此,在HashMap中不能由get()方法来判断HashMap中是否存在某个键,而应该用containsKey()方法来判断。而在Hashtable中,无论是key还是value都不能为null。

这两个类最大的不同在于Hashtable是线程安全的,它的方法是同步了的,可以直接用 在多线程环境中。而HashMap则不是线程安全的。在多线程环境中,需要手动实现同步机制。因此,在Collections类中提供了一个方法返回一个 同步版本的HashMap用于多线程的环境:

Java代码

public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) {return new SynchronizedMap<K,V>(m);}

该方法返回的是一个SynchronizedMap的实例。SynchronizedMap类是定义在Collections中的一个静态内部类。它实现了Map接口,并对其中的每一个方法实现,通过synchronized关键字进行了同步控制。

2. 潜在的线程安全问题

上面提到Collections为HashMap提供了一个并发版本SynchronizedMap。这个版本中的方法都进行了同步,但是这并不等于这个类就一定是线程安全的。在某些时候会出现一些意想不到的结果。

如下面这段代码:

Java代码

// shm是SynchronizedMap的一个实例
if(shm.containsKey('key')){shm.remove(key);
}

这段代码用于从map中删除一个元素之前判断是否存在这个元素。这里的 containsKey和reomve方法都是同步的,但是整段代码却不是。考虑这么一个使用场景:线程A执行了containsKey方法返回 true,准备执行remove操作;这时另一个线程B开始执行,同样执行了containsKey方法返回true,并接着执行了remove操作;然 后线程A接着执行remove操作时发现此时已经没有这个元素了。要保证这段代码按我们的意愿工作,一个办法就是对这段代码进行同步控制,但是这么做付出 的代价太大。

在进行迭代时这个问题更改明显。Map集合共提供了三种方式来分别返回键、值、键值对的集合:

Java代码

Set<K> keySet();Collection<V> values();Set<Map.Entry<K,V>> entrySet();

在这三个方法的基础上,我们一般通过如下方式访问Map的元素:

Java代码

Iterator keys = map.keySet().iterator();while(keys.hasNext()){map.get(keys.next());
}

在这里,有一个地方需要注意的是:得到的keySet和迭代器都是Map中元素的一个“视图”,而不是“副本”。问题也就出现在这里,当一个线程正在迭代Map中的元素时,另一个线程可能正在修改其中的元素。此时,在迭代元素时就可能会抛出ConcurrentModificationException异常。为了解决这个问题通常有两种方法,一是直接返回元素的副本,而不是视图。这个可以通过

集合类的 toArray()方法实现,但是创建副本的方式效率比之前有所降低,特别是在元素很多的情况下;另一种方法就是在迭代的时候锁住整个集合,这样的话效率就更低了。

3. 更好的选择:ConcurrentHashMap

效率低下的HashTable容器

HashTable容器使用synchronized来保证线程安全,但在线程竞争激烈的情况 下HashTable的效率非常低下。因为当一个线程访问HashTable的同步方法时,其他线程访问HashTable的同步方法时,可能会进入阻塞 或轮询状态。如线程1使用put进行添加元素,线程2不但不能使用put方法添加元素,并且也不能使用get方法来获取元素,所以竞争越激烈效率越低。

锁分段技术

HashTable容器在竞争激烈的并发环境下表现出效率低下的原因是所有访问HashTable的线程都必须竞争同一把锁,那假如容器里有多把 锁,每一把锁用于锁容器其中一部分数据,那么当多线程访问容器里不同数据段的数据时,线程间就不会存在锁竞争,从而可以有效的提高并发访问效率,这就是 ConcurrentHashMap所使用的锁分段技术,首先将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据 的时候,其他段的数据也能被其他线程访问。

java5中新增了ConcurrentMap接口和它的一个实现类 ConcurrentHashMap。ConcurrentHashMap提供了和Hashtable以及SynchronizedMap中所不同的锁机 制。Hashtable中采用的锁机制是一次锁住整个hash表,从而同一时刻只能由一个线程对其进行操作;而ConcurrentHashMap中则是 一次锁住一个桶。ConcurrentHashMap默认将hash表分为16个桶,诸如get,put,remove等常用操作只锁当前需要用到的桶。 这样,原来只能一个线程进入,现在却能同时有16个写线程执行,并发性能的提升是显而易见的。

上面说到的16个线程指的是写线程,而读操作大部分时候都不需要用到锁。只有在size等操作时才需要锁住整个hash表。

在迭代方面,ConcurrentHashMap使用了一种不同的迭代方式。在这种迭代方式中,当iterator被创建后集合再发生改变就不再是抛出ConcurrentModificationException,取而代之的是在改变时new新的数据从而不影响原有的数据,iterator完成后再将头指针替换为新的数据,这样iterator线程可以使用原来老的数据,而写线程也可以并发的完成改变。

特别说明:尊重作者的劳动成果,转载请注明出处哦~~~http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt215

SynchronizedMap和ConcurrentHashMap 区别相关推荐

  1. hashmap的特性?HashMap底层源码,数据结构?Hashmap和hashtable ConcurrentHashMap区别?

    1.hashmap的特性? 允许空键和空值(但空键只有一个,且放在第一位) 元素是无序的,而且顺序会不定时改变 key 用 Set 存放,所以想做到 key 不允许重复,key 对应的类需要重写 ha ...

  2. SynchronizedMap和ConcurrentHashMap有什么区别

    SynchronizedMap实现上在调用Map的所有方法是,对整个map进行了同步! public V put(K key, V value) {synchronized (mutex) {retu ...

  3. 【转】HashMap、TreeMap、Hashtable、HashSet和ConcurrentHashMap区别

    转自:http://blog.csdn.net/paincupid/article/details/47746341 一.HashMap和TreeMap区别 1.HashMap是基于散列表实现的,时间 ...

  4. SynchronizedMap和ConcurrentHashMap的深入分析

    转自:http://blog.sina.com.cn/s/blog_5157093c0100hm3y.html 在开始之前,先介绍下Map是什么? javadoc中对Map的解释如下: An obje ...

  5. HashMap、TreeMap、Hashtable、HashSet和ConcurrentHashMap区别

    2019独角兽企业重金招聘Python工程师标准>>> 1.HashMap.TreeMap都继承AbstractMap抽象类:TreeMap实现SortedMap接口,所以TreeM ...

  6. java hashtable 并发_Java 并发容器 —— Hashtable 与 Collections.synchronizedMap(HashMap) 的区别...

    Hashtable 部分源码 以 Hashtable 的 put 方法为例: Hashtable 保证线程安全的方式在 方法前加上 synchronized 关键字(锁的是类的实例) Collecti ...

  7. hashmap put复杂度_集合类HashMap,HashTable,ConcurrentHashMap区别?

    作者简介: 华哥 10年+后端开发工作经验, 主要分享:关于java体系的知识,如:java基础知识/数据结算/算法,Spring/MyBatis/Netty源码分析,高并发/高性能/分布式/微服务架 ...

  8. hashmap hashtable concurrenthashmap区别

    https://www.cnblogs.com/heyonggang/p/9112731.html

  9. JAVA面试知识点个人整理

    本文是一些JAVA面试的基本知识点个人整理,方便自己记忆回顾,摘自ThinkWon大神的系列文章JAVA面试题. 文章目录 静态内部类 == 和equal 参数传递 BIO,NIO,AIO File的 ...

最新文章

  1. 手把手教你怎么在linux安装c++编译器
  2. ProxyStrike运行bug解决办法
  3. 查询数据库表名,数据表信息,MySQL Key值(PRI, UNI, MUL)的含义
  4. java 基础 --静态
  5. 数据结构-荷兰国旗问题
  6. 项目: 打字母游戏【c++/c】
  7. 从 2015 年起的未来五年内有哪些创业方向 | PMcaff-产品
  8. 动态规划在求解传递闭包问题中的应用(JAVA)--Warshell算法
  9. Camera 图像处理原理分析
  10. 存储过程出错会回滚吗_一个人做梦过程中不小心挂了,梦境会继续吗?
  11. Android的 EditText的inputType类型
  12. linux下mysql用户_linux下mysql用户管理方法
  13. innodb为什么写入数据快_重要,知识点:InnoDB的插入缓冲
  14. 精密单点定位/PPP软件GAMP学习之一
  15. [leetcode] 69 Sqrt(x)
  16. 我的理想是学计算机,我的理想作文(精选10篇)
  17. word文档设置不同的页眉页脚
  18. 制作可被svchost调用的服务(上)
  19. SPSS实现系统聚类
  20. drcom上网登录窗不弹出_无线网络连接后不能弹出浏览器登录页面是怎么回事?

热门文章

  1. C# 基础补遗(未完待续)
  2. Java基础篇:什么是异常,异常处理的基础是什么?
  3. java之关系运算符
  4. Yii2数据库操作的各种写法
  5. asp.net MVC之 自定义过滤器(Filter)
  6. 域内计算机策略应用顺序
  7. 水溶彩铅的特点技法运用
  8. Android的多媒体框架OpenCore介绍
  9. FTP+SSL(加密的ftp)
  10. 【重点】LeetCode 24. Swap Nodes in Pairs