• 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路漫漫兮其修远,吾将上下而求索。
    本文持续更新中。。。。

  • 相关阅读:
    弄明白python reduce 函数
    Python 2与Python 3兼容性的写法,需要一个特殊的包 from __future__ import print_function 用法
    人工智能数学参考---8、常用激活函数
    常用激活函数(激励函数)理解与总结
    人工智能数学参考---7、核函数应用
    [粘贴]环绕闸极不能让三星在3nm工艺领先台积电
    查看java所有的线程信息
    【转载】 Sqlserver使用Left函数从最左边开始截取固定长度字符串
    值初始化和默认初始化的区别
    map的综合例子
  • 原文地址:https://www.cnblogs.com/gujiewei/p/9670585.html
Copyright © 2020-2023  润新知