美文网首页
HashMap深入解析

HashMap深入解析

作者: Android深夜食堂 | 来源:发表于2020-11-10 14:50 被阅读0次

    兄弟姐妹

    HashMap:快,遍历顺序不确定,非线程安全
    Hashtable:遗留类,线程安全,只有一个线程能写,并发性能较差
    LinkedHashMap:记录插入顺序
    ConcurrentHashMap:线程安全,分段锁

    HashMap是什么

    从结构实现来讲,HashMap是数组+链表+红黑树(JDK1.8增加了红黑树部分)实现的,如下如所示。


    HashMap结构

    重要组成:
    Node:实现了Map.Entry接口,本质是就是一个映射(键值对)。
    Node[] table:哈希桶数组
    int threshold:所能容纳的k-v对极限(table.length * load factor)
    final float loadFactor:负载因子
    int modCount:结构变化次数(put新的算,但是覆盖value不算)
    int size:当前map中的k-v数量

    设计思路

    本质:空间成本和时间成本之间权衡

    其实就是在根据实际情况确定哈希桶数组的大小,并在此基础上设计好的hash算法减少Hash碰撞。
    那么通过什么方式来控制map使得Hash碰撞的概率又小,哈希桶数组(Node[] table)占用空间又少呢?答案就是好的Hash算法和扩容机制。

    在HashMap中,哈希桶数组table的长度length大小必须为2的n次方(一定是合数),这是一种非常规的设计,常规的设计是把桶的大小设计为素数。相对来说素数导致冲突的概率要小于合数。主要是为了在取模和扩容时做优化,同时为了减少冲突,HashMap定位哈希桶索引位置时,也加入了高位参与运算的过程。

    原理实现

    1.确定哈希桶数组索引位置
    hash()、取模运算的巧妙(来计算该对象应该保存在table数组的哪个索引处,当length = 2^n时,h&(length-1) = h%length,&比%更高效)


    取模运算

    2.分析HashMap的put方法
    putVal()


    put()

    3.扩容机制
    遍历旧的数组和所有node,重新计算hash,再refresh。
    区别1.7和1.8(引入红黑树)


    分布散列的时候
    很极端

    小结

    1.扩容是特别消耗性能的,在能估算map大小的时候,可以初始化一个数值。
    2.HashMap是线程不安全的,会造成死循环
    3.jdk1.8中的红黑树对HashMap的性能优化

    拓展

    Hash哈希

    • 可变数据类型的操作改变,导致哈希值的改变

    ConcurrentHashMap

    • 分段锁
    • 对于size()的统计

    参考

    Java8系列之重新认识HashMap
    漫画:什么是ConcurrentHashMap?

    相关文章

      网友评论

          本文标题:HashMap深入解析

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