HashMap和Hashtable的区别

简介: HashMap和Hashtable的区别

【1】HashMap和HashTable异同

HashMap和Hashtable都实现了Map接口,但决定用哪一个之前先要弄清楚它们之间的分别。

主要的区别有:



  • 线程安全性–同步(synchronization),
  • 键值是否允许为null,
  • 类继承,
  • 初始化及扩容
  • 迭代器以及速度。


① 线程安全


HashMap是非synchronized,而Hashtable是synchronized。Hashtable 所有的元素操作都是 synchronized 修饰的,而 HashMap 并没有。


这意味着Hashtable是线程安全的,多个线程可以共享一个Hashtable。而如果没有正确的同步的话,多个线程是不能共享HashMap的。Java 5提供了ConcurrentHashMap,它是HashTable的替代,比HashTable的扩展性更好。


HashTable只能由一个线程操作, ConcurrentHashMap可以让一个线程操作第一个Segment,另一个线程操作另一个Segment

② NULL


Hashtable 是不允许键或值为 null 的,HashMap 的键值则都可以为 null(只有一个键允许为null)。


HashMap几乎可以等价于Hashtable,除了HashMap是非synchronized的,并可以接受null(HashMap可以接受为null的键(key)和值(value),而Hashtable则不行)。


为什么 Hashtable 是不允许 KEY 和 VALUE 为 null, 而 HashMap 则可以?


Hashtable中如果key/ value 为 null 会直接抛出空指针异常,而 HashMap 的逻辑对 null 作了特殊处理。

③ 类继承

Hashtable如下:

public class Hashtable<K,V>
    extends Dictionary<K,V>
    implements Map<K,V>, Cloneable, java.io.Serializable {


HashMap如下:

public class HashMap<K,V> extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable {


可以看出两者继承的类不一样,Hashtable 继承了 Dictionary类,而 HashMap 继承的是 AbstractMap 类。

Dictionary 是 JDK 1.0 添加的,很古老的一个字典类。其javadoc如下所示:

Dictionary是键值对映射类的抽象父类,例如Hashtable。
每一个键和值都是一个object。每个键最多关联一个值。
给定一个Dictionary对象和一个键,关联的元素可以被找到。
任何非 null 对象都可以用作键和值。
通常,这个类的实现应该使用equals方法来确定两个键是否相同
注意:这个类已经过时。新的实现应该实现Map接口,而不是继承这个类


④ 初始化和容量扩容

HashMap 的初始容量为:16,Hashtable 初始容量为:11,两者的负载因子默认都是:0.75。

当现有容量大于总容量 * 负载因子时,HashMap 扩容规则为当前容量翻倍,Hashtable 扩容规则为当前容量翻倍 + 1。


⑤ 迭代器

另一个区别是HashMap的迭代器(Iterator)是fail-fast迭代器,而Hashtable的Enumerator迭代器不是fail-fast的。


所以当有其它线程改变了HashMap的结构(增加或者移除元素),将会抛出ConcurrentModificationException,但迭代器本身的remove()方法移除元素则不会抛出ConcurrentModificationException异常。


但这并不是一个一定发生的行为,要看JVM的实现。这同样也是Enumeration和Iterator的区别。


参考博文:浅谈从fail-fast机制到CopyOnWriteArrayList使用

⑥ 速度与性能

由于Hashtable是线程安全的也是synchronized,所以通常它比HashMap要慢。如果你不需要同步,只需要单一线程,那么使用HashMap性能要好过Hashtable。


如果要线程安全又要保证性能,建议使用 JUC 包下的 ConcurrentHashMap。


【2】相关重要术语

① sychronized意味着在一次仅有一个线程能够更改Hashtable。


就是说任何线程要更新Hashtable时要首先获得同步锁,其它线程要等到同步锁被释放之后才能再次获得同步锁更新Hashtable。HashTable将底层整个hash表都锁了起来,故而在多线程的环境下,使用HashTable虽然安全但是性能十分低下。


另外需要注意的是HashTable并非绝对安全,比如在复合操作的情况下,如下所示:

if(!table.contains(XX)){
  //如果在这中间,被其他线程拿到了锁呢?
  table.put(XX);
}

② fail-fast机制

"快速失败"也就是fail-fast,它是Java集合的一种错误检测机制。


当多个线程对集合进行结构上的改变的操作时,有可能会产生fail-fast机制。记住是有可能,而不是一定。


例如:假设存在两个线程(线程1、线程2),线程1通过Iterator在遍历集合A中的元素,在某个时候线程2修改了集合A的结构(是结构上面的修改,而不是简单的修改集合元素的内容),那么这个时候程序就会抛出 ConcurrentModificationException 异常,从而产生fail-fast机制。


但其它线程可以通过set()方法更改集合对象是允许的,因为这并没有从“结构上”更改集合。但是假如已经从结构上进行了更改,再调用set()方法,将会抛出IllegalArgumentException异常。


结构上的更改指的是类似于删除或者插入一个元素,这样会影响到map的结构。

③ 我们能否让HashMap同步?

HashMap可以通过下面的语句进行同步:

Map m = Collections.synchronizeMap(hashMap);
// 或者直接使用ConcurrentHashMap(JDK1.5);
目录
相关文章
|
1月前
|
存储 开发者
HashMap和Hashtable的key和value可以为null吗,ConcurrentHashMap呢
HashMap的key可以为null,value也可以为null;Hashtable的key不允许为null,value也不能为null;ConcurrentHashMap的key不允许为null
|
1月前
|
Java
Java基础之 JDK8 HashMap 源码分析(中间写出与JDK7的区别)
这篇文章详细分析了Java中HashMap的源码,包括JDK8与JDK7的区别、构造函数、put和get方法的实现,以及位运算法的应用,并讨论了JDK8中的优化,如链表转红黑树的阈值和扩容机制。
21 1
|
1月前
|
存储 缓存 Java
【用Java学习数据结构系列】HashMap与TreeMap的区别,以及Map与Set的关系
【用Java学习数据结构系列】HashMap与TreeMap的区别,以及Map与Set的关系
33 1
|
3月前
|
存储 安全 Java
一天十道Java面试题----第二天(HashMap和hashTable的区别--------》sleep、wait、join)
这篇文章是关于Java面试的第二天笔记,涵盖了HashMap与HashTable的区别、ConcurrentHashMap的实现原理、IOC容器的实现方法、字节码的概念和作用、Java类加载器的类型、双亲委派模型、Java异常体系、GC如何判断对象可回收、线程的生命周期及状态,以及sleep、wait、join、yield的区别等十道面试题。
一天十道Java面试题----第二天(HashMap和hashTable的区别--------》sleep、wait、join)
|
3月前
|
存储 Java
【Java集合类面试七】、 JDK7和JDK8中的HashMap有什么区别?
JDK7中的HashMap使用数组加链表解决冲突,而JDK8增加了红黑树结构以优化链表过长时的性能,提高查找效率。
|
3月前
|
安全 Java
【Java集合类面试十五】、说一说HashMap和HashTable的区别
HashMap和Hashtable的主要区别在于Hashtable是线程安全的,不允许null键和值,而HashMap是非线程安全的,允许null键和值。
|
3月前
|
安全 Java
【Java集合类面试十六】、HashMap与ConcurrentHashMap有什么区别?
HashMap是非线程安全的,而ConcurrentHashMap通过减少锁粒度来提高并发性能,检索操作无需锁,从而提供更好的线程安全性和性能。
|
3月前
|
存储 安全 Java
Hashtable 和 HashMap 的区别
【8月更文挑战第22天】
149 0
|
4月前
|
存储 安全 Java
Java面试题:请解释Java内存模型,并说明如何在多线程环境下使用synchronized关键字实现同步,阐述ConcurrentHashMap与HashMap的区别,以及它如何在并发环境中提高性能
Java面试题:请解释Java内存模型,并说明如何在多线程环境下使用synchronized关键字实现同步,阐述ConcurrentHashMap与HashMap的区别,以及它如何在并发环境中提高性能
36 0
|
5月前
|
消息中间件 存储 缓存
面试题--HashMap和TreeMap的区别和应用场景有啥区别?
然后底层调用key的hashCode()方法得出hash值; 过哈希表哈希算法,将hash值转换成数组的下标(注1),下标位置上如果没有任何元素,就把Node添加到这个位置上。如果说下标对应的位置上有值。此时,就会拿着key和链表上每个节点的key进行equal。如果所有的equals方法返回都是false,那么这个新的节点将被添加到链表的末尾。如其中有一个equals返回了true,那么这个节点的value将会被覆盖,如果最终长度大于8就会转成红黑树,红黑树插入;
42 3