HashMap的ReHash图解

大城市里の小女人 提交于 2020-04-06 18:26:00

昨天在看redis的hash扩容时提到了与java的hashmap类似,之前一直没有仔细研究过,翻了几篇博客,选了容易理解的一片转载下。

  • resize方法
void resize(intnewCapacity)
{
    Entry[] oldTable = table;
    intoldCapacity = oldTable.length;
    ......
    //创建一个新的Hash Table
    Entry[] newTable =new Entry[newCapacity];
    //将Old Hash Table上的数据迁移到New Hash Table上
    transfer(newTable);
    table = newTable;
    threshold = (int)(newCapacity * loadFactor);
}
  • transfer方法
void transfer(Entry[] newTable)
{
    Entry[] src = table;
    intnewCapacity = newTable.length;
    //下面这段代码的意思是:
    //  从OldTable里摘一个元素出来,然后放到NewTable中
    for(int j = 0; j < src.length; j++) {
        Entry<K,V> e = src[j];
        if(e != null) {
            src[j] =null;
            do{
                Entry<K,V> next = e.next;
                //获取元素在新表中的位置索引
                int i = indexFor(e.hash, newCapacity);
                //将新表中的元素赋值给当前元素e的next
                e.next = newTable[i];
                //头插法的链表,表头插入
                newTable[i] = e;
                //循环下一个元素
                e = next;
            }while (e != null);
        }
    }
}

单线程下的ReHash

 

  • 用key mod 一下表的大小(也就是数组的长度)。
  • 最上面的是old hash 表,其中的Hash表的size=2, 所以key = 3, 7, 5,在mod 2以后都冲突在table[1]这里了。
  • 接下来的三个步骤是Hash表 resize成4,然后所有的<key,value> 重新rehash的过程

 

详细描述可以看下面这张图:

并发下的Rehash

  1. 假设我们有两个线程。我用红色和浅蓝色标注了一下。
do{
    Entry<K,V> next = e.next;// <--假设线程一执行到这里就被调度挂起了
    inti = indexFor(e.hash, newCapacity);
    e.next = newTable[i];
    newTable[i] = e;
    e = next;
}while (e != null);

而我们的线程二执行完成了。于是我们有下面的这个样子。

注意,因为Thread1的 e 指向了key(3),而next指向了key(7),其在线程二rehash后,指向了线程二重组后的链表。我们可以看到链表的顺序被反转后。

  1. 线程一被调度回来执行。
  • 先是执行 newTalbe[i] = e;
  • 然后是e = next,导致了e指向了key(7),
  • 而下一次循环的next = e.next导致了next指向了key(3)

3、线程一继续执行

把key(7)摘下来,放到newTable[i]的第一个,然后把e和next往下移

4、环形链接出现

e.next = newTable[i] 导致 key(3).next 指向了 key(7)
注意:此时的key(7).next 已经指向了key(3), 环形链表就这样出现了。


    当我们的线程一调用到HashTable.get(11)时,悲剧就出现了——Infinite Loop
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!