分布式下hashMap陷入死循环问题

HashMap数据结构

我需要简单地说一下HashMap这个经典的数据结构。

HashMap通常会用一个指针数组(假设为table[])来做分散所有的key,当一个key被加入时,会通过Hash算法通过key算出这个数组的下标i,然后就把这个 插到table[i]中,如果有两个不同的key被算在了同一个i(因为一些值的hash算法的结果值是一样的,所以以下标也就一样了),那么就叫冲突,又叫碰撞,这样会在table[i]上形成一个链表。

我们知道,如果table[]的尺寸很小,比如只有2个,如果要放进10个keys的话,那么碰撞非常频繁,于是一个O(1)的查找算法,就变成了链表遍历,性能变成了O(n),这是Hash表的缺陷。

所以,Hash表的尺寸和容量非常的重要。一般来说,Hash表这个容器当有数据要插入时,都会检查容量有没有超过设定的thredhold,如果超过,需要增大Hash表的尺寸,但是这样一来,整个Hash表里的元素都需要被重算一遍。这叫rehash,这个成本相当的大。

rehash就是说当hash的size不够时,就会进行扩容,扩容的时候需要重新计算元素的数组下标 
1、重新分配一个新的Entry数组 
2、重新计算原来元素的在新数组中的下标(比较耗资源)

正常rehash过程 :

数据准备 
在size=2的HashMap中按照顺序添加5, 7, 3这三个key,假设按照mod 2的算法来计算元素数组下标,那么key 5,7,3都会落在下标为1的数组桶中(发生hash冲突),如下图: 
这里写图片描述

把HashMap的size扩容为4后,正常rehash的过程

所以这是一个正常的rehash过程了。

并发下的rehash过程

当两个并发线程thread1和thread2都同时进入到transfer时,也即是,刚好thread1和thread2都要对HashMap进行扩容,万一这个时候thread1执行下面的代码时,被线程调度器挂起了,而thread2则正常的把扩容的操作做完。
这个时候对于thread1的情况是:


对于thread2的情况是:

这个时候,thread1拥有执行权限了,则继续它的扩容操作,等thread1扩容完后就产生了一个环形链表了。

这时候thread1一半时是:

但是这时候hash里key(7).next 已经指向了key(3),线程2那里已经有指向了,所以,这时候的结构是:

这个时候,如果有个get请求,就有可能发生死循环,一直在链表中绕来绕去的,没法终止。
next一直在key(3)、key(7)中获取。

所以以后在分布式中,还是用ConcurrentHashMap或是HashTable。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值