1. Hashtable 和 HashMap

(1)区别,这两个类主要有以下几方面的不同:
Hashtable和HashMap都实现了Map接口,但是Hashtable的实现是基于Dictionary抽象类。
 
在HashMap中,null可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null。 
当get()方法返回null值时,即可以表示 HashMap中没有该键,也可以表示该键所对应的值为null。
 因此,在HashMap中不能由get()方法来判断HashMap中是否存在某个键,而应该用containsKey()方法来判断。
 而在Hashtable中,无论是key还是value都不能为null 。
 
   这两个类最大的不同在于:
(1)Hashtable是线程安全的,它的方法是同步了的,可以直接用在多线程环境中。
(2)而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异常。

为了解决这个问题通常有两种方法,
(1)一是直接返回元素的副本,而不是视图。这个可以通过
集合类的 toArray() 方法实现,但是创建副本的方式效率比之前有所降低,
特别是在元素很多的情况下;
(2)另一种方法就是在迭代的时候锁住整个集合,这样的话效率就更低了。

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线程可以使用原来老的数据。

而写线程也可以并发的完成改变。

HashMap HashTable ConcurrentHashMap的更多相关文章

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

    注: 今天看到的一篇讲hashMap,hashTable,concurrentHashMap很透彻的一篇文章, 感谢原作者的分享. 原文地址: http://blog.csdn.net/zhanger ...

  2. 彻底搞懂HashMap,HashTable,ConcurrentHashMap之关联.

    注: 今天看到的一篇讲hashMap,hashTable,concurrentHashMap很透彻的一篇文章, 感谢原作者的分享.  原文地址: http://blog.csdn.net/zhange ...

  3. HashMap,HashTable,concurrentHashMap,LinkedHashMap 区别

    HashMap 不是线程安全的 HashTable,concurrentHashMap 是线程安全 HashTable 底层是所有方法都加有锁(synchronized) 所以操作起来效率会低 con ...

  4. hashmap,hashTable concurrentHashMap 是否为线程安全,区别,如何实现的

    线程安全类 在集合框架中,有些类是线程安全的,这些都是jdk1.1中的出现的.在jdk1.2之后,就出现许许多多非线程安全的类. 下面是这些线程安全的同步的类: vector:就比arraylist多 ...

  5. Java集合——HashMap,HashTable,ConcurrentHashMap区别

    Map:“键值”对映射的抽象接口.该映射不包括重复的键,一个键对应一个值. SortedMap:有序的键值对接口,继承Map接口. NavigableMap:继承SortedMap,具有了针对给定搜索 ...

  6. HashMap/Hashtable/ConcurrentHashMap区别

    HashMap:每个隔间都没锁门,有人想上厕所,管理员指给他一个隔间,里面没人的话正常用,里面有人的话把这个人赶出来然后用. 优点,每个人进来不耽误都能用:缺点,每一个上厕所的人都有被中途赶出来的危险 ...

  7. HhashMap HashTable ConcurrentHashMap

    hashMap hashTable concurrentHashMap hashMap的效率高于hashTable,hashMap是线程不安全的,并发时hashMap put方法容易引起死循环,导致c ...

  8. HashMap HashTable和ConcurrentHashMap的区别

    HashMap和Hashtable都实现了Map接口,其主要的区别有:线程安全性,同步(synchronization),以及效率. HashMap和Hashtable基本上没啥区别,除了HashMa ...

  9. 沉淀再出发:java中的HashMap、ConcurrentHashMap和Hashtable的认识

    沉淀再出发:java中的HashMap.ConcurrentHashMap和Hashtable的认识 一.前言 很多知识在学习或者使用了之后总是会忘记的,但是如果把这些只是背后的原理理解了,并且记忆下 ...

随机推荐

  1. [na]完全理解icmp协议

    1.ICMP出现的原因 在IP通信中,经常有数据包到达不了对方的情况.原因是,在通信途中的某处的一个路由器由于不能处理所有的数据包,就将数据包一个一个丢弃了.或者,虽然到达了对方,但是由于搞错了端口号 ...

  2. 常用的NodeJS模块

    图片处理 1.Manipulate images 官网:http://github.com/aheckmann/gm ImageMagick和GraphicsMagick主要用于图片的创建.编辑.合成 ...

  3. 使用flow捕获js错误提高代码质量

    本文将介绍Flow及其主特性.下面分别从如何安装设置,如何添加类型注释,如何在运行时自动去掉注释等方面来介绍. 安装 目前Flow兼容的操作系统有Mac OS X,Linux(64位),Windows ...

  4. python-计算数据的相关性

    先解释下什么叫数据的相关性: 计算两个数组的平均值,如果两个数组中的两个值都大于平均值或者都小于平均值,则得到true. 如果一个大于平均值一个小于平均值,则得到false.最后计算true和fals ...

  5. linux系统卡解决方案

    1.查看内存使用率 free -g 运行结果: 2.查看磁盘使用率 df -h 运行结果: 3.查看磁盘IO iostat -x 1 运行结果: 60表示60秒钟刷新一次 4.查看CPU使用情况 to ...

  6. git(8):常用命令

    Git常用操作命令收集: 1) 远程仓库相关命令 检出仓库:$ git clone git://github.com/jquery/jquery.git 查看远程仓库:$ git remote -v ...

  7. 【Cmd】那些年,我们迷恋的cmd命令(一)

    小续 还记得,那些年玩hack的朋友吗,现在玩这个的,基本都是小孩子了(俗称脚本小子). 还记得,那些年敲过的命令吗,现在的孩子,都用工具了(叫工具党). 孩子们,健康的网络环境需要大家一起去维护. ...

  8. LeetCode: Minimum Depth of Binary Tree 解题报告

    Minimum Depth of Binary Tree Given a binary tree, find its minimum depth. The minimum depth is the n ...

  9. java 多线程 29 :多线程组件之 Exchanger

    Exchanger Exchanger,从名字上理解就是交换.Exchanger用于在两个线程之间进行数据交换,注意也只能在两个线程之间进行数据交换.线程会阻塞在Exchanger的exchange方 ...

  10. Java SWT编程基础

    SWT常用组件列表及使用 https://blog.csdn.net/u013310025/article/details/52939452 SWT编程基础-控件和图形资源 https://blog. ...