SynchronizedMap和ConcurrentHashMap同步方式比较
在开始之前,先介绍下Map是什么?
javadoc中对Map的解释如下:
An object that maps keys to values . A map cannot contain duplicate keys; each key can map to at most one value.
The Map interface provides three collection views, which allow a map'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用于多线程的环境:
1 public static <K,V> Ma<K,V> synchronizedMap(Map<K,V> m) {
2 return new SynchronizedMap<K,V>(m);
3 }
该方法返回的是一个SynchronizedMap 的实例。SynchronizedMap类是定义在Collections中的一个静态内部类。它实现了Map接口,并对其中的每一个方法实现,通过synchronized 关键字进行了同步控制。
2. 潜在的线程安全问题
上面提到Collections为HashMap提供了一个并发版本SynchronizedMap。这个版本中的方法都进行了同步,但是这并不等于这个类就一定是线程安全的。在某些时候会出现一些意想不到的结果。
如下面这段代码:
1 // shm是SynchronizedMap的一个实例
2 if(shm.containsKey('key')){
3 shm.remove(key);
4 }
这段代码用于从map中删除一个元素之前判断是否存在这个元素。这里的containsKey和reomve方法都是同步的,但是整段代码却不是。考虑这么一个使用场景:线程A执行了containsKey方法返回true,准备执行remove操作;这时另一个线程B开始执行,同样执行了containsKey方法返回true,并接着执行了remove操作;然后线程A接着执行remove操作时发现此时已经没有这个元素了。要保证这段代码按我们的意愿工作,一个办法就是对这段代码进行同步控制,但是这么做付出的代价太大。
在进行迭代时这个问题更改明显。Map集合共提供了三种方式来分别返回键、值、键值对的集合:
1 Set<K> keySet();
2
3 Collection<V> values();
4
5 Set<Map.Entry<K,V>> entrySet();
在这三个方法的基础上,我们一般通过如下方式访问Map的元素:
1 Iterator keys = map.keySet().iterator();
2
3 while(keys.hasNext()){
4 map.get(keys.next());
5 }
在这里,有一个地方需要注意的是:得到的keySet和迭代器都是Map中元素的一个“视图”,而不是“副本” 。问题也就出现在这里,当一个线程正在迭代Map中的元素时,另一个线程可能正在修改其中的元素。此时,在迭代元素时就可能会抛出 ConcurrentModificationException异常。为了解决这个问题通常有两种方法,一是直接返回元素的副本,而不是视图。这个可以通过
集合类的 toArray() 方法实现,但是创建副本的方式效率比之前有所降低,特别是在元素很多的情况下;另一种方法就是在迭代的时候锁住整个集合,这样的话效率就更低了。
3. 更好的选择: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线程可以使用原来老的数据,而写线程也可以并发的完成改变。
原文地址:https://www.cnblogs.com/infinityu/articles/3188266.html
SynchronizedMap和ConcurrentHashMap同步方式比较的更多相关文章
- SynchronizedMap和ConcurrentHashMap 区别
详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt215 SynchronizedMap和ConcurrentHashMap的深 ...
- Hashtable、synchronizedMap、ConcurrentHashMap 比较
详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcytp18 Hashtable.synchronizedMap.Concurren ...
- Collections.synchronizedMap()、ConcurrentHashMap、Hashtable之间的区别
为什么要比较Hashtable.SynchronizedMap().ConcurrentHashMap之间的关系?因为常用的HashMap是非线程安全的,不能满足在多线程高并发场景下的需求. 那么为什 ...
- Java中SynchronizedMap与ConcurrentHashMap的对比
如何使用 概述 ConcurrentHashMap: 线程安全: 其将整个Hash桶进行了分段segment,也就是将这个大的数组分成了几个小的片段segment,而且每个小的片段segment上面都 ...
- 测试HashTable、Collections.synchronizedMap和ConcurrentHashMap的性能
对于map的并发操作有HashTable.Collections.synchronizedMap和ConcurrentHashMap三种,到底性能如何呢? 测试代码: package com. ...
- Java容器:HashTable, synchronizedMap与ConcurrentHashMap
首先需要明确的是,不管使用那种Map,都不能保证公共混合调用的线程安全,只能保证单条操作的线程安全,在这一点上各Map不存在优劣. 前文中简单说过HashTable和synchronizedMap,其 ...
- Collections.synchronizedMap()与ConcurrentHashMap的区别
前面文章提到Collections.synchronizedMap()与ConcurrentHashM两者都提供了线程同步的功能.那两者的区别在哪呢?我们们先来看到代码例子. 下面代码实现一个线 ...
- Collections.synchronizedMap()与ConcurrentHashMap区别
Collections.synchronizedMap()与ConcurrentHashMap主要区别是:Collections.synchronizedMap()和Hashtable一样,实现上在调 ...
- C# 的TCP Socket (同步方式)
简单的c# TCP通讯(TcpListener) C# 的TCP Socket (同步方式) C# 的TCP Socket (异步方式) C# 的tcp Socket设置自定义超时时间 C# TCP ...
- java笔记--关于线程同步(7种同步方式)
关于线程同步(7种方式) --如果朋友您想转载本文章请注明转载地址"http://www.cnblogs.com/XHJT/p/3897440.html"谢谢-- 为何要使用同步? ...
随机推荐
- Unity3D中实现按资源名称自动化命名打包AssetBundle
首先把模型变成预制体 一般当需要打包成AssetBundle的资源不多时,可以自己通过AssetLabels窗口手动命名,然后再打包,但是当需要打包的资源过多时,一个一个的去手动编辑就特别的麻烦,因此 ...
- word生成产生错误的原因
技术背景 很多时候我们网站或者系统需要提供一些word文件,例如证明.docx或者订单.docx等文件供用户下载打印等. 用Java操作word文档,毫无疑问,当下最流行apache poi,对于po ...
- 单个Java文件连接数据库demo
在单个java文件中,尝试连接数据库,跟python的模块包安装方式很接近,已经测试成功,把博客写一下,记录下来. 首先把jdb的驱动包下载下来,就是一个jar包,下面是官网下载地址 官网下载 ...
- Python 自动化中三种等待时间的详解
1.强制等待 强制等待是最简单的一种等待方式,强制让浏览器等待X秒,不管当前操作是否完成,是否可以进行下一步操作,都必须等X秒的时间. 使用方法:time.sleep(X) .在python中是基于t ...
- C/C++ union联合体介绍
C/C++ union联合体介绍 文章参考:https://blog.csdn.net/mooneve/article/details/92703036 目录 C/C++ union联合体介绍 1. ...
- (Yocto)Imx8mp的时间结构
1.构成图 #kernel\time\timekeeping.c #drivers\rtc\class.c 1.time date source 解释 rx8010sj: 自己定制的开发板 ...
- OC基础 - isMemberOfClass | isKindOfClass
isMemberOfClass | isKindOfClass 1 - 猜想以下代码输出的结果 1 #import <Foundation/Foundation.h> 2 #import ...
- OSPF的安全认证
OSPF的安全认证 OSPF通过LSA报文同步状态信息,协议根据LSA提供的状态信息,快速实行全网路由的建立.也就是一通百通,一变则变.坏处就是有人搞破坏,一坏则百坏.为防止网络破坏活动,实行认证(明 ...
- RTC@@@Real-Time Clock(实时时钟的简称)及电路问题分析
RTC@@@Real-Time Clock(实时时钟的简称) 实时时钟(Real-Time Clock)是PC主板上的晶振及相关电路组成的时钟电路的生成脉冲,提供稳定的时钟信号给后续电路用.主要功能有 ...
- fetch 小分析
includes\database\prefetch.inc line 385 public function fetchField($index = 0) { return $this->fe ...