Hashtable与HashMap异同比较

引言

Hashtable的淘汰开始于它的“t”没有大写,hh~。
Hashtable 是Java中第一批用来实现hash的数据结构,但是长江后浪推前浪,Hashtable逐渐退出舞台,本文就HashMap和Hashtable的差异进行比较和总结。

差异比较


一、hash函数差异以及 K,V 参数要求

Hash数据结构的第一个关键是hash函数实现,即hash值的获取办法,差异如下:
HashMap:

//Map的put方法实际上调用了putVal方法,有单独的hash函数方法;
public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
}
//Map的hash函数
static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

Hashtable:

//value为空,抛出空指针异常
if (value == null) {
    throw new NullPointerException();
}
Entry<?,?> tab[] = table;
//hash值则是直接调用hashcode方法获得
int hash = key.hashCode();
//index索引取正之后再取余;
int index = (hash & 0x7FFFFFFF) % tab.length;        

通过源码,我们可以看见,Hashtable的K和V是不能为空的,而HashMap则考虑了K、V为空的情况。
其中,K为空,则hash值置0,value为空,Map照样放进去;


二、synchronized差异

看Hashtable 里面的函数,我们会发现,函数声明时都会带有一个synchronized关键字,而HashMap没有。
这个会有什么影响呢?
我们知道,synchronized关键字是用来线程间进行同步的,即当多个线程想要对同一个Hashtable操作时,只有一个可以获得权限,而其他的得等到该线程运行完毕才能对Hashtable操作。毫无疑问,对于单线程程序来说,这肯定会降低运行的速度。但是,对于HashMap来说,他就不是多线程安全的。
于是在这个点上,HashMap提供两个方法弥补这个缺陷:

  • 使用ConcurrentHashMap;
    这个方法在规模和速度上都来的比Hashtable优秀;
  • 利用 Map m = Collections.synchronizeMap(hashMap) 实现synchronized;

三、Enumerator 与 Iterator

HashMap 的 iterator是fail-fast机制的,而Hashtable的enumerator不是。

The iterators returned by all of this class’s “collection view methods” are fail-fast: if the map is structurally modified at any time after the iterator is created, in any way except through the iterator’s own remove method, the iterator will throw a ConcurrentModificationException.

fail-fast机制: 创建iterator之后,如果不是调用iterator的remove方法,任何改变HashMap结构的操作都会导致抛出ConcurrentModificationException。
这样做的意义在于:如果有多线程修改HashMap,iterator能够快速发现,而不会去做一些”冒险“的事情。
但是,要注意的是,fail-fast机制并不一定是同步多线程才能触发的,单线程也行,如下代码所示:

public static void main(String[] args) {
        LinkedList<String>  ll= new LinkedList<String>();
        ll.add("1");
        ll.add("2");
        for(Iterator<String> iterator = ll.iterator();iterator.hasNext();){
            String content = iterator.next();
            System.out.println(content);
            if(content.equals("2"))
                ll.add("3");
        }
    }

output:

Exception in thread "main" java.util.ConcurrentModificationException
    at java.util.LinkedList$ListItr.checkForComodification(Unknown Source)
    at java.util.LinkedList$ListItr.next(Unknown Source)
    at test.A.main(A.java:13)

所以,从这点上来看,fail-fast只是给了我们一种检查bug的方法,但利用这个机制来确保程序的正确性不是一个好的选择。


四、HashMap的注意事项

HashMap add时的顺序和输出时的顺序不一样。hash内部的排序机制就是如此,在存储时就是根据hash获得索引位置,本身即是乱序,如果想要add顺序和输出顺序一致,可以使用LinkedHashMap结构,里面维护了一个双向链表来实现维持顺序;

结语

Hashtable已经逐渐被淘汰,虽然还在更新,但也只是做特殊使用,官方文档也提醒着大家尽量使用HashMap优化程序,同时也提供了相应的thread-safe方法来弥补HashMap的缺点。
Code路漫漫兮其修远,吾将上下而求索。
本文持续更新中。。。。

posted @ 2018-07-21 21:29  顾杰伟  阅读(207)  评论(0编辑  收藏  举报