HashMap

HashMap

HashMap是Java容器里面非常重要的一个类,下面来剖析下HashMap的亮点。

hash
将不同长度的输入通过hash算法变成固定长度的输出,该输出值就是散列值。一般的,输入长度远大于输出长度。也就是说,同样的输出可以对应多个输入,这时候我们称之为hash冲突

hash冲突的处理方法

  1. 开放寻址法:当hash冲突发生时,从当前冲突位置往后找数组的空位,填入数据
  2. 链地址法:当发生hash冲突时,以链表的方式将数据插入到对应的数组位置后面
  3. 再哈希法:将冲突的hash值再次进行hash运算,直到没有冲突为止

位运算
HashMap的数组长度一定是2^n,所以可以运用位运算进行快速定位数组下标。假设数组长度为a,hash值为b,b%a=b&(a-1)。

可以在其他场景下看到位运算的影子

  1. 权限控制,增加权限用或运算、删除权限用与非运算、查看是否拥有某个权限用与运算
  2. 简单可逆加密(1^1=0;0 ^ 1=1),其中第一个1是明文,0是密文,最后一个1得到最开始的明文
  3. NIO中通过位运算判断请求过来的事件类型

JDK1.7中HashMap死循环分析
单线程下HashMap不会发生死循环,但是多线程环境下,在1.7版本的HashMap中可能发生死循环,导致CPU占用100%。

正常的扩容操作是这个流程。HashMap的扩容在put操作中会触发扩容,主要是下面三个方法:

添加元素的时候出发扩容条件,出发resize(int)方法:
在这里插入图片描述

创建新数组后,需要将旧数组元素转移到新数组:
在这里插入图片描述
旧数组元素转移到新数组的逻辑,采用头插法
在这里插入图片描述
综合来说,HashMap一次扩容的过程:

  1. 取当前table的2倍作为新table的大小
  2. 根据算出的新table的大小new出一个新的Entry数组来,名为newTable
  3. 轮询原table的每一个位置,将每个位置上连接的Entry,算出在新table上的位置,并以链表形式连接
  4. 原table上的所有Entry全部轮询完毕之后,意味着原table上面的所有Entry已经移到了新的table上,HashMap中的table指向newTable

举个例子:
现在hashmap中有三个元素,Hash表的size=2, 所以key = 3, 7, 5,在mod 2以后都冲突在table[1]这里了。
在这里插入图片描述
按照方法的代码:
在这里插入图片描述
对table[1]中的链表来说,进入while循环,此时e=key(3),那么next=key(7),经过计算重新定位e=key(3)在新表中的位置,并把e=key(3)挂在newTable[3]的位置
在这里插入图片描述
在这里插入图片描述
这样循环下去,将table[1]中的链表循环完成后,于是HashMap就完成了扩容
在这里插入图片描述
在这里插入图片描述
到这里为止,单线程下的HashMap扩容不会发生问题,接下来分析并发下的HashMap扩容

初始的HashMap还是:
在这里插入图片描述
我们现在假设有两个线程并发操作,都进入了扩容操作,我们以颜色进行区分两个线程:
在这里插入图片描述
回顾我们的扩容代码,我们假设,线程1执行到Entry<K,V> next = e.next;时被操作系统调度挂起了,而线程2执行完成了扩容操作
在这里插入图片描述
于是,在线程1,2看来,就应该是这个样子
在这里插入图片描述
接下来,线程1被调度回来执行:
1)在这里插入图片描述
2)
在这里插入图片描述
3)
在这里插入图片描述
4)

在这里插入图片描述
5)
在这里插入图片描述
6)
在这里插入图片描述
7)
在这里插入图片描述
循环列表产生后,一旦线程1调用get(11,15之类的元素)时,就会进入一个死循环的情况,将CPU的消耗到100%。

总结
HashMap之所以在并发下的扩容造成死循环,是因为,多个线程并发进行时,因为一个线程先期完成了扩容,将原Map的链表重新散列到自己的表中,并且链表变成了倒序,后一个线程再扩容时,又进行自己的散列,再次将倒序链表变为正序链表。于是形成了一个环形链表,当get表中不存在的元素时,造成死循环。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值