女朋友撒娇让我教她HashMap

人世仙家本自殊,何须相见向中途。惊鸿瞥过游龙去,漫恼陈王一事无。
嗨,大家好,我是洛神,性别男。一个来自快乐星球的程序员。

前言

众所周知,HashMap作为面试中的老油条,充斥在每一个公司的面试中,可以说,HashMap为求职者和面试官之间搭建起了一座“友谊”桥梁。既然如此重要,那么今天,洛神就带领各位复习一下HashMap的经典问题以及引申一下相关的知识点。

场景代入:

面试官:“小伙子,了解过HashMap吗?”
你:(慌得一批)“大概知道一些”。
面试官:“你知道HashMap???太好了,你通过了”。
你:“?????。。。。!!!!!!”。
醒醒!以上场景,仅在不吃花生米喝多了的情况下会出现,在真实情况中,面试官恨不得让你手写底层源码。

在这里插入图片描述

正文

HashMap为什么是线程不安全的?可能有许多小伙伴会愣一下,但如果我问,为什么HashTable是线程安全的?你可能会毫不犹豫的回答,因为HashTable使用了synchronized锁来保证方法的安全性。这里,可能就引申出了一个问题:
HashTable线程安全,为什么在项目中不使用HashTable而是使用HashMap呢?
HashTable虽然可以保证线程安全,但是因为synchronize在同一时间只有一把锁,其他线程必须等到拿到锁的线程执行完成后,才能去抢锁,因此带来的问题就是效率问题,当一个线程访问hashtable的同步方法时,其他线程再次尝试访问的时候,会进入阻塞或者轮询状态,慢慢的,线程的竞争会越来越激烈。效率也会越来越低。
面试官可能会接着问:
那我应该怎么样来提升并发情况下的效率问题同时还保证线程安全呢?
答:
用ConcurrentHashMap呀!它使用了分段锁技术来提高并发度,每个段使用一把锁,因此不在同一段的数据不会互相影响。ConcurrentHashMap的实现非常精巧,在底层利用了大量的volatile,final,CAS等lock-free技术来减少锁竞争对性能的影响。
面试官:“小伙子,那你能不能说一下,hashMap为什么是线程不安全的呀?”(一脸和蔼~)
在这里插入图片描述
你:(中指)
答:HashMap的不安全性主要是因为在并发情况下的put以及get时的resize(扩容)操作导致的,可能会使线程死锁并让CPU的使用率飙升100。下面请允许我一一道来:
首先,并发情况下的put操作可能会造成多线程数据不一致。
例如:线程A希望put一个KV对到HashMap中,它要先计算记录要落到的桶的索引坐标,然后再获取该桶里面的链表头结点,然而刚要执行插入的时候,线程A的时间片用完了,线程B被调度执行了,B重复了A的操作,并且成功的执行了插入操作,而此时我们假设线程A和线程B计算出的桶的索引坐标是一致的,那么线程A重新调度执行后,并不知道链表头结点已经失效,仍然会执行put操作,此时,B插入的数据就会被A覆盖,从而造成了数据不一致的行为。
其次,并发下的get操作可能会因为resize问题造成死循环。(JDK1.8之后采用了尾插法,扩容造成的问题已经解决。本次以JDK1.7为例)文字太多,白嫖了一段举例说明,大家看一下:
我们假设有两个线程同时需要执行resize操作,我们原来的桶数量为2,记录数为3,需要resize桶到
4,原来的记录分别为:[3,A],[7,B],[5,C],在原来的map里面,我们发现这三个entry都落到了第二个桶里面。
假设线程thread1执行到了transfer方法的Entry next = e.next这一句,然后时间片用完了,此时的e = [3,A], next = [7,B]。线程thread2被调度执行并且顺利完成了resize操作,需要注意的是,此时的[7,B]的next为[3,A]。此时线程thread1重新被调度运行,此时的thread1持有的引用是已经被thread2 resize之后的结果。线程thread1首先将[3,A]迁移到新的数组上,然后再处理[7,B],而[7,B]被链接到了[3,A]的后面,处理完[7,B]之后,就需要处理[7,B]的next了啊,而通过thread2的resize之后,[7,B]的next变为了[3,A],此时,[3,A]和[7,B]形成了环形链表,在get的时候,如果get的key的桶索引和[3,A]和[7,B]一样,那么就会陷入死循环。
正如我刚才所说,JDK1.8以后使用了尾插法,在扩容时会保持链表原本的顺序,就不会出现链表死循环的问题了。
综上两点所述,就是为什么HashMap不是线程安全的原因。

结尾

这是洛神CSDN的第一篇博客,也决定以后的写作风格就是精简一些,把内容多拆分一些(没错,我就是怕一篇写太多,后面没的水了),以上的内容也是洛神之前面试碰到过的,如有不对的地方,还请各位多多指教!

在这里插入图片描述

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值