ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

某大厂一面八股文(HashMap八连问)

2022-06-17 23:32:27  阅读:140  来源: 互联网

标签:八股文 HashMap synchronized 链表 线程 红黑树 put 八连


1.HashMap的工作原理是什么?

HashMap的底层是通过数组加单向链表来实现的,在数组中每一个元素都是一个链表结构,,而链表中的每一个节点又是一个Entry对象,这个Entry对象它是用来存储指针的K-V键值对,也就是键值对的这个值,在HashMap中有两个比较重要的方法,一个是get(),一个是put(),先说一下put(),在存储K-V键值对的时候,我们首先会调用一个hash()方法,通过hash()方法可以计算出Key的Hash值,从而得到一个十进制的数字,那么这个数字和数组的长度-1取模就可以得到一个结果,也就是数组的下标,我们可以给根据下标去找到数组中存储的这个单向链表,然后把链表中的每一个Key和要插入的Key进行equals()比较,如果是相等的话,我们就直接更新这个Value值,如果不相等的话,就把新的K-V值put()到这个链表中去,在put过程中,当哈希表中存储的键值对超过了数组长度乘以负载因子的时候,就会将这个数组扩容为两倍,还有就是在插入链表的时候,如果链表长度超过了我们默认设置的阈值为8的时候,节点的数据结构就会自动转化为红黑树的结构,接下来再说get()方法,get方法和put方法调用也比较类似,同样也会调用hash方法,然后对Key进行计算,也就是去模拟以数组长度减1,计算出对应的这个Key的一个下标,然后我们在遍历这个下表对应的这个链表元素在进行equals()比较,如果key相同的话,就把这个元素取出并且返回给用户,最后总结,HashMap最核心的原理是利用Hash值来计算出下标的位置,,然后再用equals比较,equals主要是解决Hash冲突的问题。

2.哈希表中链表超长以后转化成红黑树,为什么会使用红黑树?

红黑树是二叉查找树的一种,那么它的查找算法就相当于二分的查找,红黑树的时间复杂度O(logn)在数据比较多的时候回比列表的查询的时间复杂度O(n)要好很多。

3.那你认为HashMap可不可以不使用链表,而直接使用红黑树呢,或者使用二叉查找树或者AVL树之类的数据结构?

我认为之所以没有选择一开始就使用红黑树可能是因为时间和空间的折中考虑吧,在Hash冲突比较小的时候,即使转化为红黑树之后在时间复杂度上所产生的效果,其实也并不是特别大,而且在put的时候效率也可能会降低,毕竟每次put都要进行非常复杂的红黑树这种旋转算法旋转操作,宁外在空间上,每个节点都需要维护更多的一个指针这就显得有点得不偿失。,最后就是HashMap之所以选择红黑树而不是二叉查找树,我认为最主要的原因是,二叉树在一些极端情况下,它会变成一个倾斜的结构,然后查找效率就会退化成跟链表差不多了,而红黑树它是一种平衡树,它可以防止这种退化,所以可以保持平衡,因为红黑树又不想其它的完全的平衡二叉树那样有那样的严格的平衡条件,所以平衡树的插入效率要比完全平衡二叉树要高,所以HashMap在选择红黑树既可以避免极端情况下的退化,也可以兼顾查询和插入的这种效率。

4.HashMap是线程安全的吗?

HashMap在设计的时候是针对单线程环境来设计的,所以在多线程环境下,它不是线程安全的

5.在多线程并发环境下,如果需要一个Hash结构的话,你如何实现呢?

如果在多线程并发的环境,我们可以使用ConcurrentHashMap来实现这样一个需求

6.你对ConcurrentHashap的底层实现原理有了解吗?

ConcurrentHashMap要分为两种情况进行分析,一个是在jdk1.7,然后是1.8之后它们之间的差别比较大,那么在jdk1.7的话,它的底层实现原理是使用数组加链表来实现的,然后使用了一种分段锁来保证线程安全,它是将数组分成16段,也就是给每个Segment来配一把锁,然后再读每个Segment的时候,就要先获取对应的锁,所以它是最多能有16个线程并发去操作,到了jdk1.8之后,它跟HashMap一样也引入了红黑树的这个结构,同样在并发处理方面,不再使用分段锁的方式,而是CAS加synchronized关键字这种方式来实现,更加细腻度的锁,相当于是把锁的控制控制在更加细腻的哈希桶的级别,然后在写入键值对的时候,这个可以锁住哈希桶的这种链表的这种头节点,这样的话就不会影响到其它的哈希桶的写入,从而去提高对并发处理的这种处理能力。

7.你刚才提到ConcurrentHashMap中使用的是synchronized关键字,那如果使用ReentrantLock来作为锁,是不是也可以呢?

理论上来讲的话因该是可以的,但是我认为这个synchronized关键字会更好一点吧,因为在jdk1.6之后对synchronized关键字也进行了一些优化,它里面引入了偏向锁,然后轻量级锁以及重量级锁,之前在ReentrantLock中是没有的,并且jdk版本的升级,synchronized也在进一步的进行优化,因为这个ReentrantLock使用Java代码来实现的,所以在之后的话也很难有特别大的提升空间,所以优先使用synchronized次之才会选择ReentrantLock

8.介绍以下synchronized关键字对于锁的一些优化吧?

synchronized它默认采用的是偏向锁,然后在程序运行中始终是只有一个线程去获取这个synchronized的这么一个锁那么Java对象中的话,会记录一个线程的ID,我们在下次获取synchronized的所的时候,只需要去比对这个线程的ID就行了,在运行过程中如果出现第二个线程去请求synchronized锁的时候,这里就分为两种情况,在没有发生并发竞争锁的情况,这个synchronized就会自动升级为轻量锁,这个时候第二个线程就会尝试自旋锁的方式来获取锁,因为很快就能拿到锁,所以第二个线程也不会阻塞。如果出现这种就是两个线程竞争的情况的话,这个synchronized它会升级为重量级锁,那么这个时候就是,只会有一个线程能够获取到锁那么另外一个线程它会阻塞,然后要等待第一个线程释放锁之后,才能拿到所。

 

标签:八股文,HashMap,synchronized,链表,线程,红黑树,put,八连
来源: https://www.cnblogs.com/2246781190zyc/p/16387378.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有