Java并发 - J.U.C并发容器类Map - HashMa

作者: 右耳菌 | 来源:发表于2022-06-21 22:29 被阅读0次

    基于前面的Java并发 - J.U.C并发容器类Map - HashMap简单分析,我们接着来对HashMap的相关知识进行一个补充。

    HashMap插入数据的思路

    • HashMap插入数据的思路
    1. 对应的数组下标的元素为空,直接放
    2. key 是不是同一个key,如果是则进行value的替换
    3. key 不是同一个,且数组有元素,则判断是链表还是树
      • 是链表:判断是否达到了树的要求,没达到就挂链表,否则变成红黑树
      • 是红黑树:挂到红黑树后边的节点中去

    链表长度==8 的时候,会自动转换成红黑树

        /**
         * The bin count threshold for using a tree rather than list for a
         * bin.  Bins are converted to trees when adding an element to a
         * bin with at least this many nodes. The value must be greater
         * than 2 and should be at least 8 to mesh with assumptions in
         * tree removal about conversion back to plain bins upon
         * shrinkage.
         */
        static final int TREEIFY_THRESHOLD = 8;
    

    但是即便如此,就算加入了红黑树,如果数组长度一定的情况下,大量数据放入map中,发生hash碰撞的几率就越大,那么红黑树必然也会越来越庞大,照样会影响查询的效率。本质来说,这是数组的长度限制导致的,所以数组的扩容很是必要。


    HashMap的扩容

    • 数组的扩容:当数组满足空间被占用的75%的时候(默认的填充因子是0.75f),会进行扩容,数组容量和填充因子都向左平移1位 << 1 即呈2倍扩容。
      此时会进行创建新的数组,然后再对旧的数组及挂在在元素下的链表(或红黑树)进行迁移。
      迁移的情況:
    1. 遍历老数组,如果有元素且只有一个元素,那么直接进行迁移
    2. 数组的元素下是一个链表,那么就遍历链表,取模然后插入新的数组
    3. 数组的元素下是一个红黑树,那么就打散树之后再遍历树的元素,取模然后插入新的数组中

    HashMap的总结

    这部分在Java并发 - J.U.C并发容器类Map - HashMap简单分析 也有描述:

    • HashMap是数组+链表构成的,JDK1.8之后,加入了红黑树.
    • HashMap默认数组初始化大小为16,如果瞎设置数字,它会自动调整成 2 的倍数.
    • HashMap链表在长度为 8 之后,会自动转换成红黑树,数组扩容之后,会打散红黑树,重新设置.
    • HashMap扩容变化因子是0.75,也就是数组的3/4被占用之后,开始扩容。
    • 在第一次调用PUT方法之前,HashMap是没有数组也没有链表的,在每次put元素之后,开始检查(生成)数组和链表.

    与HashTable的比较

    大体是一致的,只是暴露的方法里边多了 synchronized 修饰符,确保了线程安全,但是不推荐使用,主要是在多线程调用的时候,一个同步的修饰符会导致性能下降,与Map设计的初衷提升访问速度相违背。所以对于HashTable只要知道它线程安全的原因是加入了synchronized修饰符

    • get 方法中加入了synchronized修饰符
        public synchronized V get(Object key) {
            Entry<?,?> tab[] = table;
            int hash = key.hashCode();
            int index = (hash & 0x7FFFFFFF) % tab.length;
            for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
                if ((e.hash == hash) && e.key.equals(key)) {
                    return (V)e.value;
                }
            }
            return null;
        }
    

    如果觉得有收获就点个赞吧,更多知识,请点击关注查看我的主页信息哦~

    相关文章

      网友评论

        本文标题:Java并发 - J.U.C并发容器类Map - HashMa

        本文链接:https://www.haomeiwen.com/subject/ezyevrtx.html