高并发下的hashMap--抄自小灰
1、什么是rehash?
rehash就是hashmap在扩容时候的一个步骤。
hashmap的容量是有限的,当经过多次元素插入,使得hashmap达到一定饱和度时,key映射位置发生冲突的几率会逐渐提高,这时候,hashmap需要扩展它的长度,也就是进行resize。
影响发生resize的因素有两个:
1、capacity:hashmap的当前长度。
2、loadfactor:hashmap的负载因子,默认值是0.75f。
综合来说,当hashmap.size>=capacityloadfactor。用文字来说,就是hashmap的当前长度大于等于(总长度0.75)
2、resize的步骤:
a、扩容
创建一个新的entry空数组,长度是原数组的2倍。
b、rehash
遍历原entry数组,把所有的entry重新hash到新数组
3、hashmap是非线程安全的!
假设一个hashmap已经到了resize的临界点,此时有两个线程A和B,在同一时刻对hashmap进行put操作:
经过如上两个步骤后,就达到了resize的条件,两个线程各自进行resize的第一步,也就是扩容:
这时候,两个线程都走到了rehash的步骤,回顾一下rehash的代码:
假如此时线程B遍历到entry3对象,刚执行完红框里的这行代码,线程就被挂起,对于线程B来说,e = entry3,next=entry2。这时候线程A进行rehash,当rehash完成后,结果如下(图中的e和next,代表线程B的两个引用)
直到这一步,看起来没有什么毛病,接下来线程B恢复,继续执行属于它自己的rehash,线程B刚才的状态是:
当执行到上面这一行时,显然i=3,因为刚才线程A对应entry3的hash结果也是3.
继续执行到这两行,entry3放入了线程B的数组下标为3的位置,并且e指向了entry2.此时e和next的指向如下:
靠。。。。看不懂了。看小灰的结论是最终链表出现了环形。
就是当调用get查找一个不存在的key,而这个key的hash结果恰好等于3的时候,由于位置3带有环形链表,所以程序将会进入死循环。。。。