HashMap底层原理

参考视频:源码学院(java架构知识——HashMap底层实现和原理(源码解析)_哔哩哔哩_bilibili

Java7:数组+链表

在调用put()时,其实执行的是先计算出key的hash值,再根据Hash值计算出Index决定了它存在数组中的哪个位置。

数组中存的是Entry,每个Entry中存的是key,value,hash,next。

上述图中的各个key/value实体的hash值如图:

当key为刘一进来时,存储位置Index为4,那么就放在数组中下标为4的地方。接着陈二存放。到了张三时,存储位置又是4,但是索引为4的地方已经存了刘一,此时如果把张三直接放入索引为4的地方,就会把刘一覆盖掉。于是就出现了链表的方式来解决:将刘一向后移动一个位置,然后把张三放到索引为4的存储空间中,并修改张三的next指向刘一,形成一个单向链表。所以HashMap的底层数据结构是数组+链表。

同理,等到key为Monkey的数据来的时候,计算得到的index也是4,此时就需要把原来index为4的张三和刘一都向后移动一个位置,将Monkey放进来,并修改next指向张三。

在执行get()获取元素时,get()中同样会根据key计算hash值,再计算下标。假设现在要获取的是key为刘一的value,计算出来的index是4,就去数组中下标为4的地方寻找,发现索引为4的地方存储的hash与刘一的hash不一致,说明不是当前元素,那么就会看索引为4的这个元素的next是否为空,如果为空,说明不存在要找的元素,如果不为空,那就去看next指向的元素hash值是否一致,如果一致,就获取value,如果不一致,继续看next是否为空,依次类推,直到找到hash一致的key。

链表:查找慢,插入删除快。

红黑树:查找快,插入删除慢。(与链表对比)

Java8:数组+链表+红黑树

在查找时需要遍历链表逐一对比,时间复杂度为O(n)。当链表越来越长时,查找的速度就会变慢。所以在java8中链表的长度达到阈值(阈值为8)时会变成红黑树。

红黑树的结构是根据hash值进行比较的,小于中间节点的在左侧,大于中间节点的在右侧,直到对比出等于某个节点时表明找到该元素。

HashMap线程安全问题:

在调用get()时是线程安全的。

在调用put()发生数组扩容的时候是线程不安全的。分析:假设现在有并发线程A和B,当A线程来get()一个key为刘一的值时,计算出来了一个hash,但此时线程B在执行put()时发生了扩容,就会导致原来的元素位置可能发生变化,比如刘一原来在索引为4的位置,扩容之后被放到了索引为6的位置,而这个时候线程A仍然根据刚才算出来的hash去下标为4的地方获取刘一,显然得到的结果是空。

线程不安全,key/value可为空。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

QYHuiiQ

听说打赏的人工资翻倍~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值