hashmap扩容 面试_hashmap经典面试问题以及答案

论坛 期权论坛 编程之家     
选择匿名的用户   2021-6-2 21:03   5041   0

c165b224a9f4ddb4d451fe6ea5497c1a.png

上一篇文章分析了hashmap的主要方法,了解了主要方法接下来好解答平时面试的问题了。

加载因子为什么是 0.75?

那加载因子为什么是 0.75 而不是 0.5 或者 1.0 呢?

首先如果加载因子比较大,那么扩容发生的频率就比较低,但是他浪费的空间比较小,不过发生hash冲突的几率就比较大,比如加载因子是1的时候,如果hashmap长度为128,那么可能hashmap的实际存储元素数量在64至128之间的时间段比较多,而这个时间段发生hash冲突就比较大,造成数组中其中一条链表较长,就会影响性能。

而当加载因子值比较小的时候,扩容的频率就会变高,因此会占用更多的空间,但是元素的存储就比较稀疏,发生哈希冲突的可能性就比较小,因此操作性能会比较高,比如设置成0.5,同样128长度的hashmap,当数量达到65的时候就会触发hashmap的扩容,扩容后长度为256,256里面只存储了65个似乎有点浪费了。

所以综合了以上情况就取了一个 0.5 到 1.0 的平均数 0.75 作为加载因子。

当有哈希冲突时,HashMap 是如何查找并确认元素的?

通过昨天分析get方法应该已经比较清楚了,如果哈希冲突,还是找到table[index]的第一个Node,然后一个一个去比对链表中的key,key一致则找到,引用put流程图其中一部分如下图:

62c0619f2526f9ecfd27899d981761ec.png

JDK 1.8 HashMap 扩容时做了哪些优化?

在 JDK 1.7 中 HashMap 是以数组加链表的形式组成的,JDK 1.8 之后新增了红黑树的组成结构,当链表大于 8 并且容量大于 64 时,链表结构会转换成红黑树结构,即使在hashcode 完全相同极端情况下,由于红黑树的特点,查找某个特定元素,也只需要O(log n)的开销,而如果查找链表,时间复杂度会退化到 O(n)。

HashMap 是线程安全的吗,为什么不是线程安全的?

通过例子来讲解这个不安全的过程,引用上一篇文章的例子,首先一个长度为8的map<Integer,V>,map已经存了key为1、9的两个值,他们都会在map的table[1]上。

1、首先线程1put一个key=17的值,当程序运行到判断key=9的下一个节点为null准备把key=17的值设置为它的下一个节点时,线程让出资源。

2、此时执行线程2,对mapput一个key=25的数据,这个数据正常作为key=9的next正常插入。

3、线程1再次拿到资源继续执行,设置key=9的next为key=17,这样线程2设置的key=25就被覆盖

以上的流程示意图如下图:

a72fc30e59637d4f9fa3ecb267f5ccc4.png

关键代码在于HashMap的put代码,详解如下图:

0d89dc072abd6225e2f7955741592399.png

HashMap 是如何导致死循环的?

说到死循环都是说jdk7的hashmap的死循环,主要在多线程情况下,多个线程对map的同时扩容造成的,jdk7扩容的关键代码如下图:

531f9e681b00fcc1aa002529abf290aa.png

可以看到jdk7比上一篇文章分析的jdk8的扩容的关键代码就简单多了,实际上就是遍历所以元素,找到在新的table下的位置,并把新table对应位置的元素设置成当前元素的next,就是所谓的头插法

那么为什么会造成死循环呢?这里简单做一个造成死循环的流程分析,如下图:

e3606c94c0f54ea5273d0806a9bd9482.png

造成死循环的原因主要在于线程1执行单key=9,并取出他的next(key=25)作为下次遍历后,线程1交出了执行权休息去了,而接着线程2吭哧吭哧的执行完扩容,扩容由于采用头插法,此时key=25那个Entry对象的next是key=9。

所以当线程1继续执行,到遍历next(key=25)时他的next变成了key=9,最终造成了两个Entry互相引用,如果后面调用map.get(41)就会刚好查询table[9],然后遍历这个链表,造成死循环!

总结

hashmap面试时主要的问题就是上面的那些了,有些可能没有覆盖到,但是只要弄懂了源码,所有问题都差不多,注意jdk8只是解决了死循环的问题,多线程下数据丢失的问题还是没有解决,所以多线程还是用ConcurrentHashMap。

有时候面试的时候可能面试官只会问“你了解hashmap吗?”,这种问题就不要想简单了直接回答一个了解就完了,而是把你理解的比如hashmap结构、主要方法实现、jdk7与jdk8的区别、jdk7可能的问题等都可以主动说出来,这样会更好!

Java程序员日常学习笔记,如理解有误欢迎各位交流讨论!

371a4411ca3d90f99661c737bee0c424.png
分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:3875789
帖子:775174
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP