美文网首页
HashMap的reHash多线程循环链表

HashMap的reHash多线程循环链表

作者: 剑书藏于西 | 来源:发表于2018-11-08 11:03 被阅读0次

HashMap put()元素时会扩容,生成一个newTable存储元素

   /** 
    * 
    * 往表中添加元素,如果插入元素之后,表长度不够,便会调用resize方法扩容 
    */  
   void addEntry(int hash, K key, V value, int bucketIndex) {  
       Entry<K,V> e = table[bucketIndex];  
       table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
       if (size++ >= threshold)  
           resize(2 * table.length);  
   }  
  
   /** 
    * resize()方法如下,重要的是transfer方法,把旧表中的元素添加到新表中
    */  
   void resize(int newCapacity) {  
       Entry[] oldTable = table;  
       int oldCapacity = oldTable.length;  
       if (oldCapacity == MAXIMUM_CAPACITY) {  
           threshold = Integer.MAX_VALUE;  
           return;  
       }  
  
       Entry[] newTable = new Entry[newCapacity];  
       transfer(newTable);  
       table = newTable;  
       threshold = (int)(newCapacity * loadFactor);  
   }
    /**
     * Transfers all entries from current table to newTable.
     */
    void transfer(Entry[] newTable, boolean rehash) {
        int newCapacity = newTable.length;
        for (Entry<K,V> e : table) {
 
            while(null != e) {
                // 重点。线程A执行到这一步时间片用完挂起
                // 设置next 
                Entry<K,V> next = e.next;
                if (rehash) {
                    e.hash = null == e.key ? 0 : hash(e.key);
                }
                // 计算旧表的元素在新表的位置
                int i = indexFor(e.hash, newCapacity); 
                /* newTable[i]指向一个链表的首元素。
                 * 这一行和下面一行把e插入到这个链表的前端
                 */
                e.next = newTable[i];
                newTable[i] = e;
                e = next;
            }
        }
  • 假设hash算法是key mod size (key%size)。
  • old 表的size=2,key = 3, 7, 5,在mod 2以后都冲突在table[1]这里了。
  • 单线程下ReHash,resize 变成4,如图


    image.png

并发下的ReHash

  1. 线程T一 在执行完 Entry<K,V> next = e.next; 这一步后挂起。

  2. 此时e = 3;next = 7;

  3. 线程T二开始执行并完成整个ReHash的过程,并把oldTable = newTable(最主要的一点,线程T二完成了oldTable的偷梁换柱);


    image.png
  4. 线程T一获得时间片重新执行;

  5. 此时第一次while循环正式开始;

  6. e指向了newTable的3,next指向了newTable的7;


    image.png

相关文章

网友评论

      本文标题:HashMap的reHash多线程循环链表

      本文链接:https://www.haomeiwen.com/subject/kiuixqtx.html