关于HashMap一些问题

HashMap在JDK7到JDK8中从单链表+数组演变为链表+数组+红黑树结构,解决死循环问题。JDK7扩容可能导致链表死循环,JDK8通过尾插法与红黑树优化,但高并发下仍可能出现循环。非线程安全的HashMap在多线程环境下推荐使用ConcurrentHashMap。JDK8中,链表长度达到8时转为红黑树,提高查找效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

第一部分,面试会遇到的问题

  1. HashMap在JDK7 到 JDK8的变化
    1. JDK1.7中,HashMap是基于单链表 + 数组的模式实现的;
    2. JDK1.8中,HashMap是基于链表+数组+红黑树的数据结构实现的;
    3. JDK1.7中插入的方式是头插法,1.8中使用的是尾插法:
      1. 1.7中基于单链表的实现,使用头插法会造成出现逆序、环形链表死循环的问题。当HashMap数据量达到总长度【Capacity】的75%(默认,具体值在HashMap类中的【LoadFactor】,即【负载因子】 , 初始化值为0.75f)时,会对HashMap进行扩容,原则上是将其长度扩大为原本的两倍,这个过程称为【resize】。resize的过程如下:
        1. 创建一个新的Entry数组,长度是原HashMap的两倍(二进制+1位);
        2. ReHash:因为长度扩大后,hash的规则也会随之改变【hash公式:index = HashCode(Key) & (Length - 1)】,所以要对HashMap进行重新Hash计算;
        3. 在多线程情况下,如果多个线程同时对一个HashMap进行添加【put】操作,并同时触发扩容,会导致在Rehash的某一时刻链表形成闭环(死循环),这个过程如果想详细了解,可以参考JDK7中HashMap的死循环 小言老师的文章,总结的非常到位。大多时候讲到这里就不需要继续深究原因了;
        4. 一般在JDK8之前想要保证线程安全,可以使用ConcurrentHashMap保证线程安全。
      2. JDK8号称可以避免死循环和倒序的问题,但是在实际应用中,有大佬发现在高并发场景下,红黑树实现时可能会出现多个树节点的Parent互相引用,仍会造成死循环的现象。【参考:JDK8中HashMap的死循环
      3. 真的到了多线程高并发的场景,老老实实用ConcurrentHashMap吧。
  2. JDK7-8中,HashMap都不是线程安全的,主要是因为put操作未加锁,在多线程的场景下会造成线程的不同步操作导致数据有效性、及时性问题。
  3. HashMap的初始大小:HashMap的初始大小是16,主要是因为:
    1. HashMap的大小Capacity是2的n次幂
    2.  2/4/8虽然可行,但是过于容易触发HashMap的扩容resize,这个过程可能会造成性能损失;
    3. 只要输入的HashCode是均匀的,hash算法也会相对均匀,初始大小16也会使该分部均匀。
  4. 为什么用ConcurrentHashMap而不用HashTable来保证线程安全: 
    1. HashTable只是用synchronized实现了同步锁
    2. 这样实现的同步锁并发度不高;
    3. ConcurrentHashMap使用了锁分段(减小锁的范围),CAS(Compare And Swap 比较并交换,乐观锁,减少上下文开销,无阻塞),在一定程度上保证了线程安全同时保证较高的并发度。
  5. JDK8中什么时候用链表,什么时候用红黑树?原因是什么?
    1. 长度达到8时由链表转换为红黑树,长度小于6时由红黑树转换为链表;
    2. 执行get操作,链表的时间复杂度是n/2 ,红黑树是 log n   (log以2为底,算对数) ;
    3. 当长度为8时,链表:8/2 = 4 红黑树 : log  8 = 3 ,此时红黑树时间效率高于链表;
    4. 当长度为4时,链表:4/2 = 2 红黑树 : log  4 = 2 ,此时时间效率相同,但是空间复杂度,链表要优于红黑树;
    5. 在4-8的区间内,通常认为红黑树效率略高于链表,但是空间复杂度远高于链表,所以还是优先使用链表结构;
    6. 实际上讲,从长度大于4时开始,红黑树的时间效率已高于链表结构,但是考虑到较高的空间复杂度,选择了链表结构,此中涉及的是时间、空间的取舍;
    7. 6-8的区间内,不会改变原本的数据结构,因为改变数据结构的操作本身就有一定开销,所以不进行数据结构的改变。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值