面试HashMap的原理

一般来说,java面试必不可少的菜品,那就是“来,讲一下HashMap的原理”  

那么今天就来讲一下HashMap的原理

先说一下JDK1.7跟JDK1.8对它的改变

  1. JDK1.7之前使用的是数组加链表,它的数据节点是一个Entry节点,它的一个内部类。HashMap JDK1.7之前的数据插入过程是使用头插法。
  2. JDK1.7跟1.8的区别就是1.7是头插法,1.8是尾插法

那么问题来了,HashMap使用头插法会造成什么问题呢?

     2. 它在调用resize它的一个扩容的过程,可能会造成在里面有一个resize的方法,它又调用了一个transfer的方法,把里面的Entry进行一个rehash

这个过程可能会造成一个链表的循环可能在下一次Get的时候出现一个死循环的情况。可能是因为没有加锁,所以也有可能多个线程并发情况下可能

数据不安全,可能我put进去,取出来还是之前的值。

下面说一下到JDK1.8的改变

  1. JDK1.8把HashMap变成一个链表加数组加红黑树的一个结构,把原的一个Entry节点也编程了一个Node节点,它的整个put的过程做了一个优化。

把改变一说,其实就差不多了解HashMap了,不知不觉中就理解了。

不过别高兴太早,如果要深究那么就要继续了解下面的内容了

HashMap的扩容机制

  1. 了解扩容机制,先了解一下Capacity这个节点,就是在初始化HashMap的时候,如果没有设置它的capacity它的默认初始容量是16,负载因子是0.75

,它会计算出一个threshold是它的一个阈值,一个扩容的阈值,如果当我在put的时候,会先检测我当前的size是不是大于这个阈值,如果大于了,会创建

出一个两倍大小的,扩大到原来两倍大,然后将原来的一个Entry进行一个resize的一个过程。

回顾一下JDK1.7是头插法,1.8是尾插法,那么头插法会死循环,线程不安全,1.8就是线程安全了吗?

面试官也许就是这样一步步的套路,你也只能是步步为营了

  1. 答案是显而易见的,不安全的,因为采用尾插法没有改变原来的数据插入的一个顺序,所以不会出现链表循环的一个过程。

已经问到这个地步了,那么肯定会问你,怎么样才能保证线程安全呢?

下面就要讲述它的一个同门师兄弟,不知师兄还是师弟哈,可以评论区留言

可以使用ConcurrentHashMap,HashTable这两个都是线程安全的,也可以加Synchronized或者Lock或Collection.Synchronize,但是ConcurrentHashMap的并发度是更高的

相对HashTable是直接对里面的方法进行了Synchronized加了一个对象锁。ConcurrentHashMap的结构就是数组加链表加红黑树,它只会锁住我目前获取到的那个Entry所在节点

的一个值,在上锁的时候也使用了CAS Synchronized JDK1.6之后对Synchronized进行一个优化锁升级的一个过程,所以他的效率是更高的。

毕竟做了那么多的事效率下降了,脸面也过不去

锁升级的过程是什么样的呢?

最开始的时候锁是支持偏向锁的,我当前获取到锁资源的这个线程会优先让它再去获取到这个锁,如果没有获取到这个锁,那么久升级成一个轻量级的,一个CAS的锁,就是

一个乐观锁,乐观锁是什么呢?乐观锁是一个比较有交换的过程,如果这个CAS没有设置成功的话,它会进行一个自旋,自旋到一定次数过后,才会升级成一个Synchroized的一个

重量级的锁,这样就保证了它的性能问题,最开始是一个无锁状态下的,然后再去检测判断去升级。

讲着讲着就越刨越深,不过面试就是这样,有些坑不知不觉就陷进去了。

如果讲有什么不对请指正,感谢支持!!!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值