HashMap、HashTable、CurrentHashMap、LinkedHashMap、TreeMap简述

HashMap

是一个 散列链表的数据结构,即“数组+链表”的结构。HashMap是非线程安全的,key和value都可以为空,数组长度为2的幂次方,用key的hash值,右移16位 & 数组(长度减1)确定index角标放置元素。
默认长度为16,扩容因子0.75,扩容方式为左移一位,即乘2。

备注:

Java 7中,并发出现“死循环”的一种情形,就是在resize过程中,迁移Entry到新桶中是产生了一个有环的链表造成的,Java 7中resize的transfer是在链表头部插入新节点,Java 8中的新节点的插入是尾部;

Java 8相对于Java 7中HashMap的区别和优化:

(1)计算hash值的方法:Java 7中会基于一个随机种子计算hash值,这样每次resize如果得到不同的随机种子,那么原来一个桶中的元素,会被“随机”散列到桶数组中,Java 8放弃了这种做法,基于key的hashCode(通过异或计算综合高位和地位),旧桶的元素如上面所说只可能散列到两个确定位置的桶中,基于好的hashCode计算,这也是随机分布的,这样可以简化了计算并且省去了随机种子的计算;
(2)红黑树的应用:桶中的链的长度超过TREEIFY_THRESHOLD(8)且长度小于MIN_TREEIFY_CAPACITY(64),则扩容,大于MIN_TREEIFY_CAPACITY,单链转换成树结构(红黑树),也就是变O(n)的查找转变为O(log n);

if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);

 final void treeifyBin(Node[] tab, int hash) {
        int n, index; Node e;
        if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
            resize();
        else if ((e = tab[index = (n - 1) & hash]) != null) {
            TreeNode hd = null, tl = null;
            do {
                TreeNode p = replacementTreeNode(e, null);
                if (tl == null)
                    hd = p;
                else {
                    p.prev = tl;
                    tl.next = p;
                }
                tl = p;
            } while ((e = e.next) != null);
            if ((tab[index] = hd) != null)
                hd.treeify(tab);
        }
    }

Hashtable

几乎可以等价于HashMap,加了同步关键字,是线程安全的,key和value都不可以为空。锁是对整个结构的锁,性能较差。

ConcurrentHashMap

ConcurrentHashMap:由于Hashtable是锁住整个hash表,性能低,ConcurrentHashMap采用了锁分段,锁住某一个Segment,即一个块。提高了效率和性能。
如图:

3.png

LinkedHashMap​

继承自HahsMap,内部有维护了一个双向链表,保存了记录的插入顺序。

TreeMap

TreeMap实现SortMap接口,能够把它保存的记录根据键排序。
默认是按键值的升序排序,也可以指定排序的比较器,当用Iterator 遍历TreeMap时,得到的记录是排过序的。

HashMap和Hashtable区别:

性能上HashMap要优于Hashtable,Hashtable是过时的,多线程操作的时候,它需要锁住整个结构,待释放同步锁之后,其他线程才能操作。
另外可以通过Collections.synchronizedMap(m)给HashMap加同步锁,这样可以实现线程安全。

另一个区别是HashMap的迭代器(Iterator)是fail-fast迭代器,而Hashtable的enumerator迭代器不是fail-fast的。所以当有其它线程改变了HashMap的结构(增加或者移除元素),将会抛出ConcurrentModificationException,但迭代器本身的remove()方法移除元素则不会抛出ConcurrentModificationException异常。但这并不是一个一定发生的行为,要看JVM。这条同样也是Enumeration和Iterator的区别。

三种类型分别在什么时候使用

1、一般情况下,我们用的最多的是HashMap。HashMap里面存入的键值对在取出的时候是随机的,它根据键的HashCode值存储数据,根据键可以直接获取它的值,具有很快的访问速度。在Map 中插入、删除和定位元素,HashMap 是最好的选择。
2、TreeMap取出来的是排序后的键值对。但如果您要按自然顺序或自定义顺序遍历键,那么TreeMap会更好。
3、LinkedHashMap 是HashMap的一个子类,如果需要输出的顺序和输入的相同,那么用LinkedHashMap可以实现,它还可以按读取顺序来排列,像连接池中可以应用。

你可能感兴趣的:(HashMap、HashTable、CurrentHashMap、LinkedHashMap、TreeMap简述)