基础大杂烩 -- 目录

-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

1. Hashtable 和 HashMap

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

    ⊙ 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用于多线程的环境:

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

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

2. 潜在的线程安全问题

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

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

  这段代码用于从map中删除一个元素之前判断是否存在这个元素。 这里的containsKey和reomve方法都是同步的,但是整段代码却不是。

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

  在进行迭代时这个问题更改明显。

  Map集合共提供了三种方式来分别返回键、值、键值对的集合:

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

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

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. HashMap HashTable ConcurrentHashMap

    1. Hashtable 和 HashMap (1)区别,这两个类主要有以下几方面的不同:Hashtable和HashMap都实现了Map接口,但是Hashtable的实现是基于Dictionary抽 ...

  8. HashMap,HashTable ,LinkedHashMap,TreeMap的区别

    Map:主要是存储键值对,不允许键重复,但可以值重复. HashMap:根据键的HashCode值来存储数据,根据键直接获取值.具有很快的访问速度,遍历时,取得的数据值的顺序都是随机的.hashMap ...

  9. HashMap, HashTable, CurrentHashMap的区别

    转载:http://www.jianshu.com/p/c00308c32de4 HashMap vs ConcurrentHashMap 引入ConcurrentHashMap是为了在同步集合Has ...

  10. HhashMap HashTable ConcurrentHashMap

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

随机推荐

  1. Zookeeper学习笔记——2 Shell和Java API的使用

    ZooKeeper的使用一般都接触不到,因为平时工作甚少直接使用ZK.但是通过手动操作一下ZK,还是能对其中的门道了解各一二. shell 常用命令 help 查看所有支持的命令 [zk: local ...

  2. 将控件画成圆角的效果(Delphi)

    最近在做一个Delphi的项目,常常要设计软件的界面,需要将控件画成圆角矩形.在Delphi中将控件画成圆角效果,可使用CreateRoundRectRgn函数.在此写了一个通用的函数,只要在用到改变 ...

  3. 安装NVIDIA驱动时禁用自带nouveau驱动

    安装英伟达驱动时,一般需要禁用自带nouveau驱动,按如下命令操作: sudo vim /etc/modprobe.d/blacklist-nouveau.conf 添加如下内容: blacklis ...

  4. chapter15中使用generator来实现异步化操作的同步化表达的例子

    在p203中作者给了一个例子,我感觉这个例子写的不好,一开始我没有看懂,因为中间有很多细节没有交代,直到看了第二个用generator来实现ajax的例子之后才有所领悟.   所以我把作者给的这个用g ...

  5. 终极解决方案:org.apache.jasper.JasperException: java.lang.IllegalStateException: getOutputStream() has already been called for this response

    一.项目 我的项目采用Spring MVC +JSP+EasyUI 做的老项目. 在做图片验证码方法时,向网页输出验证码图片的方法如下: @Override public void showCodeI ...

  6. c++设计一个无法被继承的类

    要求是该类不能被继承,但是能够像正常的类一样使用.那么一下方法就不符合题目要求: 1.构造函数和析构函数设置为private.这样就不能定义一个类的实例 2.类似于singleton模式那样,定义一个 ...

  7. llvm Array Bounds Check Elimination

    http://www.knosof.co.uk/vulnerabilities/arraybnd.html http://www.cs.utsa.edu/dmz/techrep/2010/CS-TR- ...

  8. CentOS7下 让Docker pull命令使用squid做http代理拉取目标镜像仓库的镜像

    场景,如下图所示: 服务器B具有两个网卡,分别和服务器A和服务器C互通,这里想要在服务器C上借助服务器B作为桥梁,拉取镜像仓库服务器A上的镜像. 思路也很简单,在服务器上搭建HTTP代理服务,服务器C ...

  9. OpenCV 学习笔记 06 图像检索以及基于图像描述符的搜索

    OpenCV 可以检测图像的主要特征,然后提取这些特征,使其成为图像描述符,这些图像特征可作为图像搜索的数据库:此外可以利用关键点将图像拼接 stitch 起来,组成一个更大的图像.如将各照片组成一个 ...

  10. MySQL -- Innodb的关闭

    参数innodb_fast_shutdown控制着innodb的关闭模式,有三种取值: 0:     innodb执行slow shutdown,在关闭之前要完成一次full purge和change ...