1、HashTable与HashMap

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

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

(3)HashTable是线程安全的,它的方法是同步了的,可以直接用在多线程环境中。HashMap则不是线程安全的。在多线程环境中,需要手动实现同步机制。

因此,在Collections类中提供了一个方法返回一个同步版本的HashMap用于多线程的环境:

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。这个版本中的方法都进行了同步,但是这并不等于这个类就一定是线程安全的。在某些情况下会出现一些意想不到的结果。

如下面这段代码:

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

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

考虑这么一个场景:线程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

Java 5中新增了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. HashMap HashTable和ConcurrentHashMap的区别

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

  2. 集合 HashMap 的原理,与 Hashtable、ConcurrentHashMap 的区别

    一.HashMap 的原理 1.HashMap简介 简单来讲,HashMap底层是由数组+链表的形式实现,数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的,如果定位到的数组位置不含链表 ...

  3. Java Main Differences between HashMap HashTable and ConcurrentHashMap

    转自这篇帖子:http://www.importnew.com/7010.html HashMap和Hashtable的比较是Java面试中的常见问题,用来考验程序员是否能够正确使用集合类以及是否可以 ...

  4. HashMap和Hashtable以及ConcurrentHashMap的区别

    ​ HashMap和Hashtable的区别 何为HashMap HashMap是在JDK1.2中引入的Map的实现类. HashMap是基于哈希表实现的,每一个元素是一个key-value对,其内部 ...

  5. HashMap、HashTable、ConcurrentHashMap的区别

    一.相关概念 1.Map的概念 javadoc中对Map的解释如下: An objectthat maps keys to values . Amap cannot contain duplicate ...

  6. HashMap、Hashtable和ConcurrentHashMap的区别

    HashTable 底层数组+链表实现,无论key还是value都不能为null,线程安全,实现线程安全的方式是在修改数据时锁住整个HashTable,效率低,ConcurrentHashMap做了相 ...

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

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

  8. HashTable与ConcurrentHashMap的区别

  9. HashMap、HashTable、ConcurrentHashMap、HashSet区别 线程安全类

    HashMap专题:HashMap的实现原理--链表散列 HashTable专题:Hashtable数据存储结构-遍历规则,Hash类型的复杂度为啥都是O(1)-源码分析 Hash,Tree数据结构时 ...

随机推荐

  1. CT107D电路解析

    1.译码器: 其中,A.B.C为输入端, 对应关系如下: CBA  十进制    输出(低电平) 000      0           Y0 001      1           Y1 010 ...

  2. Hibernate的批量查询——Criteria查询所有、条件、分页、统计(聚合函数)、排序

    1.查询所有的学生信息: public static void testSel() { Session session = HibernateUtils.openSession(); Transact ...

  3. 20181107 模拟赛T1:快乐传递政治正确版

    问题描述 David 有很多好朋友.有些期末季刚结束,有些人很快乐,但有些不太快乐,David 想把快乐传递给每个人,作为心理学大师,他准备了如下计划:David 的朋友中有 n 个男生和 m 个女生 ...

  4. 中心极限定理(Central Limit Theorem)

    中心极限定理:每次从总体中抽取容量为n的简单随机样本,这样抽取很多次后,如果样本容量很大,样本均值的抽样分布近似服从正态分布(期望为  ,标准差为 ). (注:总体数据需独立同分布) 那么样本容量n应 ...

  5. ServerManager.exe 0xc0000135 应用程序错误

    问题: 将 Windows Server 2016 .NET Framework移除. IIS卸载后, Server Manager.exe.事件查看器等都无法正常开启. 解决方案: 在运行中,输入C ...

  6. pyqt(day1)

    参考代码地址:https://github.com/cxinping/Pyqt5 pyqt在线帮助文档:https://www.riverbankcomputing.com/static/Docs/P ...

  7. FZU Monthly-201906 获奖名单

    FZU Monthly-201906 获奖名单 冠军: 空缺 一等奖: 陈金杰 S031702334 空缺 二等奖: 黄海东 S031702647 吴宜航 S031702645 蔡煜晖 S111801 ...

  8. sql server查看表大小

    查看SqlServer 数据库中各个表多少行 : SELECT A.NAME ,B.ROWS FROM sysobjects A JOIN sysindexes B ON A.id = B.id WH ...

  9. [Web 测试] Jest单元测试的几个指标

    三个参数代表什么? %stmts是语句覆盖率(statement coverage):是不是每个语句都执行了? %Branch分支覆盖率(branch coverage):是不是每个if代码块都执行了 ...

  10. SpringMVC(十四):SpringMVC 与表单提交(post/put/delete的用法);form属性设置encrypt='mutilpart/form-data'时,如何正确配置web.xml才能以put方式提交表单

    SpringMVC 与表单提交(post/put/delete的用法) 为了迎合Restful风格,提供的接口可能会包含:put.delete提交方式.在springmvc中实现表单以put.dele ...