HashMap与ConcurrentHashMap面试要点
HashMap底层数据结构
JDK7:数组链表
JDK8:数组链表红黑树(看过源码的同学应该知道JDK8中即使用了单向链表,也使用了双向链表,双向链表主要是为了链表操作方便,应该在插入,扩容,链表转红黑树,红黑树转链表的过程中都要操作链表)JDK8中的HashMap为什么要使用红黑树?
当元素个数小于一个阈值时,链表整体的插入查询效率要高于红黑树,当元素个数大于此阈值时,链表整体的插入查询效率要低于红黑树。此阈值在HashMap中为8JDK8中的HashMap什么时候将链表转化为红黑树?
这个题很容易答错,大部分答案就是:当链表中的元素个数大于8时就会把链表转化为红黑树。但是其实还有另外一个限制:当发现链表中的元素个数大于8之后,还会判断一下当前数组的长度,如果数组长度小于64时,此时并不会转化为红黑树,而是进行扩容。只有当链表中的元素个数大于8,并且数组的长度大于等于64时才会将链表转为红黑树。上面扩容的原因是,如果数组长度还比较小,就先利用扩容来缩小链表的长度。JDK8中HashMap的put方法的实现过程?
1。根据key生成hashcode
2。判断当前HashMap对象中的数组是否为空,如果为空则初始化该数组
3。根据逻辑与运算,算出hashcode基于当前数组对应的数组下标i
4。判断数组的第i个位置的元素(tab〔i〕)是否为空a。如果空,则将key,value封装为Node对象赋值给tab〔i〕b。如果不为空:i。如果put方法传入进来的key等于tab〔i〕。key,那么证明存在相同的keyii。如果不等于tab〔i〕。key,则:1。如果tab〔i〕的类型是TreeNode,则表示数组的第i位置上是一颗红黑树,那么将key和value插入到红黑树中,并且在插入之前会判断在红黑树中是否存在相同的key2。如果tab〔i〕的类型不是TreeNode,则表示数组的第i位置上是一个链表,那么遍历链表寻找是否存在相同的key,并且在遍历的过程中会对链表中的结点数进行计数,当遍历到最后一个结点时,会将key,value封装为Node插入到链表的尾部,同时判断在插入新结点之前的链表结点个数是不是大于等于8,如果是,则将链表改为红黑树。iii。如果上述步骤中发现存在相同的key,则根据onlyIfAbsent标记来判断是否需要更新value值,然后返回oldValue
5。modCount
6。HashMap的元素个数size加1
7。如果size大于扩容的阈值,则进行扩容JDK8中HashMap的get方法的实现过程
1。根据key生成hashcode如果数组为空,则直接返回空如果数组不为空,则利用hashcode和数组长度通过逻辑与操作算出key所对应的数组下标i
4。如果数组的第i个位置上没有元素,则直接返回空
5。如果数组的第1个位上的元素的key等于get方法所传进来的key,则返回该元素,并获取该元素的value
6。如果不等于则判断该元素还有没有下一个元素,如果没有,返回空
7。如果有则判断该元素的类型是链表结点还是红黑树结点
a。如果是链表则遍历链表
b。如果是红黑树则遍历红黑树
8。找到即返回元素,没找到的则返回空JDK7与JDK8中HashMap的不同点
1。JDK8中使用了红黑树
2。JDK7中链表的插入使用的头插法(扩容转移元素的时候也是使用的头插法,头插法速度更快,无需遍历链表,但是在多线程扩容的情况下使用头插法会出现循环链表的问题,导致CPU飙升),JDK8中链表使用的尾插法(JDK8中反正要去计算链表当前结点的个数,反正要遍历的链表的,所以直接使用尾插法)
3。JDK7的Hash算法比JDK8中的更复杂,Hash算法越复杂,生成的hashcode则更散列,那么hashmap中的元素则更散列,更散列则hashmap的查询性能更好,JDK7中没有红黑树,所以只能优化Hash算法使得元素更散列,而JDK8中增加了红黑树,查询性能得到了保障,所以可以简化一下Hash算法,毕竟Hash算法越复杂就越消耗CPU
4。扩容的过程中JDK7中有可能会重新对key进行哈希(重新Hash跟哈希种子有关系),而JDK8中没有这部分逻辑
5。JDK8中扩容的条件和JDK7中不一样,除开判断size是否大于阈值之外,JDK7中还判断了tab〔i〕是否为空,不为空的时候才会进行扩容,而JDK8中则没有该条件了
6。JDK8中还多了一个API:putIfAbsent(key,value)
7。JDK7和JDK8扩容过程中转移元素的逻辑不一样,JDK7是每次转移一个元素,JDK8是先算出来当前位置上哪些元素在新数组的低位上,哪些在新数组的高位上,然后在一次性转移ConcurrentHashMapJDK7中的ConcurrentHashMap是怎么保证并发安全的?
主要利用Unsafe操作ReentrantLock分段思想。主要使用了Unsafe操作中的:
1。compareAndSwapObject:通过cas的方式修改对象的属性2。putOrderedObject:并发安全的给数组的某个位置赋值3。getObjectVolatile:并发安全的获取数组某个位置的元素分段思想是为了提高ConcurrentHashMap的并发量,
分段数越高则支持的最大并发量越高,程序员可以通过concurrencyLevel参数来指定并发量。ConcurrentHashMap的内部类Segment就是用来表示某一个段的。每个Segment就是一个小型的HashMap的,当调用ConcurrentHashMap的put方法是,最终会调用到Segment的put方法,而Segment类继承了ReentrantLock,所以Segment自带可重入锁,当调用到Segment的put方法时,会先利用可重入锁加锁,加锁成功后再将待插入的key,value插入到小型HashMap中,插入完成后解锁。JDK7中的ConcurrentHashMap的底层原理
ConcurrentHashMap底层是由两层嵌套数组来实现的:
1。ConcurrentHashMap对象中有一个属性segments,类型为Segment〔〕;
2。Segment对象中有一个属性table,类型为HashEntry〔〕;
当调用ConcurrentHashMap的put方法时,先根据key计算出对应的Segment〔〕的数组下标j,确定好当前key,value应该插入到哪个Segment对象中,如果segments〔j〕为空,则利用自旋锁的方式在j位置生成一个Segment对象。然后调用Segment对象的put方法。
Segment对象的put方法会先加锁,然后也根据key计算出对应的HashEntry〔〕的数组下标i,然后将key,value封装为HashEntry对象放入该位置,此过程和JDK7的HashMap的put方法一样,然后解锁。在加锁的过程中逻辑比较复杂,先通过自旋加锁,如果超过一定次数就会直接阻塞等等加锁。JDK8中的ConcurrentHashMap是怎么保证并发安全的?
主要利用Unsafe操作synchronized关键字。Unsafe操作的使用仍然和JDK7中的类似,主要负责并发安全的修改对象的属性或数组某个位置的值。
synchronized主要负责在需要操作某个位置时进行加锁(该位置不为空),比如向某个位置的链表进行插入结点,向某个位置的红黑树插入结点。JDK8中其实仍然有分段锁的思想,只不过JDK7中段数是可以控制的,而JDK8中是数组的每一个位置都有一把锁。
当向ConcurrentHashMap中put一个key,value时,
1。首先根据key计算对应的数组下标i,如果该位置没有元素,则通过自旋的方法去向该位置赋值。
2。如果该位置有元素,则synchronized会加锁
3。加锁成功之后,在判断该元素的类型a。如果是链表节点则进行添加节点到链表中b。如果是红黑树则添加节点到红黑树
4。添加成功后,判断是否需要进行树化
5。addCount,这个方法的意思是ConcurrentHashMap的元素个数加1,但是这个操作也是需要并发安全的,并且元素个数加1成功后,会继续判断是否要进行扩容,如果需要,则会进行扩容,所以这个方法很重要。
6。同时一个线程在put时如果发现当前ConcurrentHashMap正在进行扩容则会去帮助扩容。JDK7和JDK8中的ConcurrentHashMap的不同点
这两个的不同点太多了。。。,既包括了HashMap中的不同点,也有其他不同点,比如:
1。JDK8中没有分段锁了,而是使用synchronized来进行控制
2。JDK8中的扩容性能更高,支持多线程同时扩容,实际上JDK7中也支持多线程扩容,因为JDK7中的扩容是针对每个Segment的,所以也可能多线程扩容,但是性能没有JDK8高,因为JDK8中对于任意一个线程都可以去帮助扩容
3。JDK8中的元素个数统计的实现也不一样了,DK8中增加了CounterCell来帮助计数,而JDK7中没有,JDK7中是put的时候每个Segment内部计数,统计的时候是遍历每个Segment对象加锁统计。
当然也有一小点点的优化措施,在这就卖个关子,需要更加深入了解的可关注微信公众号老周扯IT
有你的青春的作文那年,男孩十五,女孩十四。女孩,温柔善良,貌美如花,优秀,男孩,玩世不恭,放荡不羁,英俊。男孩成绩不好,留了一级,和女孩同班同桌。那天,男孩趴在桌子上睡觉,女孩对男孩说:……
献给老师师恩难忘作文教师节,一个不寻常的日子,一个庄严的日子,一个高尚的日子,一个美丽的日子,一个动人的日子。老师!园丁是您光荣的称号。看那枝头绽放的鲜花,是您辛勤的汗水浇灌。阳光普照,园丁……
夏日里的世外桃源作文这是一个普通的夏日,才刚刚下过雨,清新的空气中还带着些许潮湿,迎面还有丝丝的凉意,这是一个难得惬意的午后。才过了一个小羊摆尾的时间,太阳就调皮地从云里钻了出来,憋红了脸,释放出……
今日投融资亮点丨凯辉设立全球医疗基金元宇宙吸金力不减男士彩妆每经记者:唐如钰姚亚楠每经编辑:肖芮冬今日(5月24日),一级市场热点事件主要来自医疗、彩妆和元宇宙领域。具体来看,凯辉基金宣布设立凯辉全球医疗基金,管理规模为5亿……
奥迪广告涉嫌抄袭侵权法律专家解析该谁担责本报记者司宇萌5月21日是小满节气,一则由知名艺人刘德华代言的奥迪汽车广告片登上热搜。但在广告片发布当晚,快手博主北大满哥就发布了标题为被抄袭了过亿播放的文案是什么体验的……
日记开心的一天11月6日星期日晴趁着周日哥哥放假,哥哥一大早坐车,中午抵达学校。我站在学校门口,向着四处张望,一下子便能看到哥哥熟悉的面庞。我连忙兴奋地举起双手,向着哥哥的方向挥着,果……
环保为主题写一篇记叙作文环境保护是国际性的大问题,提高全民族的环境保护意识,环保意识的培养必须要从学生抓起,从学校教育抓起。下面和小编一起来看看环保为主题记叙作文怎么写吧,欢迎阅读!环保为主题记叙作文……
海啸小学生作文一个欢喜日子,一个高兴的日子,也是一个可怕的日子,更是一个悲伤的日子。在这个变化无穷的日子里。大家正为丰收而庆祝,但是吉野用火把烧了干枯的稻子。原来,是海啸来了他没有时间送信,……
师恩永不忘品学网专稿未经允许不得转载今天的太阳仿佛为您升起,今天的鲜花仿佛只为您怒放,今天的雄鹰仿佛为您展翅高飞,今天学生们的笑脸只因为您才笑得最灿烂hellip;hellip;是……
描写大海的作文600字一个暑假,爸爸妈妈带我去看大海。从车里远眺,我就看到了大海,此时的我心中已经热血沸腾。到了沙滩,啊!凉爽的海风时不时向我吹来,让我感到神清气爽。先看沙滩,几个小朋友在挖沙……
插上一双翅膀看童年初中生作文童年是一杯咖啡,有着浓浓的香味;童年是一首歌,美妙动听,婉转悠扬;童年是一只蝴蝶,五彩斑斓,振翅欲飞童年如此的美,我们怎能不忆童年?我插上一双翅膀,在童年,插上一双翅膀看童年。……
问界M5尾标被换成华为小康股份董事长回应产品好不好市场说了算本报记者王鹤见习记者冯雨瑶作为小康股份子公司赛力斯汽车有限公司与华为联合打造的高端系新能源智能汽车品牌AITO的首款车型,问界M5近日因用户抠掉赛力斯尾标,贴上华为标识而……
我喜欢夏天的作文8篇我最喜欢夏天作文400字一年的四季各有各的可爱之处。春天风景迷人,夏天热情奔放,秋天硕果累累,冬天银装素裹。每个季节都有我喜欢的地方,但是要我从这些季节里面,我最最喜欢的……
登苏仙岭小学生作文这里有个飞升亭,还有一块好大的石头,传说是苏仙升仙时留下的脚印,再看看山下,哗!好高啊!就像踩着云朵看风景今天,我们来到了位于湖南郴州市城东的苏仙岭。我们一进门就摸到了好多个福……
感恩母亲母亲卑微如青苔,庄严如晨曦,柔如江南的水声,坚如千年的寒玉,举目时,她是皓皓明月,垂首时,她是莽莽大地。题记夏天的早晨,太阳似一个调皮的孩子,早早地起床。随着渐渐地……
把爱分给陌生人初三作文每个人都有一颗充满爱的心,人们通过它传递着爱,给家人、朋友一切自己所熟悉的人,但我们往往忽略了身边来往的陌生人。有一次,我照例乘上了730路公交车,站在了卖票员的位子旁边……
节约用水从我做起初中作文我曾经看到过一个广告,有一盆花,被套上了塑料袋,通之一杯水,广告提醒大家到最后不要用这种方法取水。水是那么的important(重要的),有一些人常常喜欢浪费我们身边宝贵的淡水……
节约用水的资料100字篇一:咱们每天用的水都是干干净净的水,我们不能浪费水源。世界上有千千万万个人,每人喝一杯水,世界上的淡水就会越来越少,所以我们要节约用水。节约用水是我们的好习惯,人人都要……
中秋节中秋节安溪县第十小学五年3班黄端容每年农历八月十五日,是我国的传统节日中秋节。一到这个节日,我都会迫不及待地拿着月饼跑到阳台赏月。那时天空中的月亮很大很圆,月亮的光芒照耀大地就……
2015七年级回忆多彩的暑假生活作文多彩的暑假生活我爱春光明媚的春天,我爱秋高气爽的秋天,我爱冰天雪地的冬天,我更爱骄阳似火的夏天。因为夏天的到来,就是我暑假的。到来。盼啊!盼啊!快热的暑假终于来了。在这骄阳似火的……
关于面对作文600字以上我们确实活得艰难,一要承受种种外部的压力,更要面对自己内心的困惑。为大家分享关于面对作文,一起来看看吧!关于面对作文1宝剑锋从磨砺出,梅花香自苦寒来。不经一番彻骨寒,怎得……
母爱打动我800字作文篇一:母爱打动我母亲,犹如黑夜里一盏为我照亮的明灯,让我有前进的目标;母亲,犹如一位优秀的导师,为我讲解了人生中不懂的事情,让我在人生路上少了荆棘;母亲,犹如暴风雨中的一……
奶奶的眼睛作文范文眼睛是心灵之窗,那么,对于眼睛的描写来讲,就是相当重要的,因为可以反映出这个人的真实内心或者是局部的特征。为大家分享了奶奶的眼睛作文,欢迎借鉴!奶奶的眼睛作文1我的奶奶今……
摸黑我们都起过早,我们也都摸过黑。睡觉的时间随着年龄的增长而一推再推,但睡觉的欲望却没有消退。当然也会有翻来覆去睡不着的时候,心里要做的事情太多,这是必然的。人越大也就越渴望睡一个……