ConcurrentHashMap的源码分析-为什么要做高低位的划分

要想了解这么设计的目的,我们需要从ConcurrentHashMap的根据下标获取对象的算法来看,在putVal方法中1018行

(f = tabAt(tab, i = (n - 1) & hash)) == null

通过(n-1) & hash来获得在table中的数组下标来获取节点数据,【&运算是二进制运算符,1 & 1=1,其他都为0】

假设我们的table长度是16, 二进制是【0001 0000】,减一以后的二进制是 【0000 1111】

假如某个key的hash值=9,对应的二进制是【0000 1001】,那么按照(n-1) & hash的算法

0000 1111 & 0000 1001 =0000 1001 , 运算结果是9 

当我们扩容以后,16变成了32,那么(n-1)的二进制是 【0001 1111】

仍然以hash值=9的二进制计算为例

0001 1111 & 0000 1001 =0000 1001 ,运算结果仍然是9 

我们换一个数字,假如某个key的hash值是20,对应的二进制是【0001 0100】,仍然按照(n-1) & hash算法,分别在16为长度和32位长度下的计算结果

16位: 0000 1111 & 0001 0100=0000 0100

32位: 0001 1111 & 0001 0100 =0001 0100

从结果来看,同样一个hash值,在扩容前和扩容之后,得到的下标位置是不一样的,这种情况当然是不允许出现的,所以在扩容的时候就需要考虑,

而使用高低位的迁移方式,就是解决这个问题.

大家可以看到,16位的结果到32位的结果,正好增加了16. 

比如 20 & 15=4 、20 & 31=20 ; 4-20 =16

比如 60 & 15=12 、60 & 31=28; 12-28=16 

所以对于高位,直接增加扩容的长度,当下次hash获取数组位置的时候,可以直接定位到对应的位置。

这个地方又是一个很巧妙的设计,直接通过高低位分类以后,就使得不需要在每次扩容的时候来重新计算hash,极大提升了效率。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值