源码解析JDK1.8-HashMap链表成环的问题解决方案

前言

  上篇文章详解介绍了HashMap在JDK1.7版本中链表成环的原因,今天介绍下JDK1.8针对HashMap线程安全问题的解决方案。

jdk1.8 扩容源码解析

public class HashMap<K,V> extends AbstractMap<K,V>
   implements Map<K,V>, Cloneable, Serializable {
   
   // jdk1.8 HashMap扩容源码
final Node<K,V>[] resize() {
       
       Node<K,V>[] oldTab = table;
       
       // 到@SuppressWarnings都是计算newTab的newCap和threshold容量
       int oldCap = (oldTab == null) ? 0 : oldTab.length;
       int oldThr = threshold;
       int newCap, newThr = 0;
       if (oldCap > 0) {
           if (oldCap >= MAXIMUM_CAPACITY) {
               threshold = Integer.MAX_VALUE;
               return oldTab;
          }
           else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
                    oldCap >= DEFAULT_INITIAL_CAPACITY)
               newThr = oldThr << 1; // double threshold
      }
       else if (oldThr > 0) // initial capacity was placed in threshold
           newCap = oldThr;
       else {               // zero initial threshold signifies using defaults
           newCap = DEFAULT_INITIAL_CAPACITY;
           newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
      }
       if (newThr == 0) {
           float ft = (float)newCap * loadFactor;
           newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
                    (int)ft : Integer.MAX_VALUE);
      }
       threshold = newThr;
       @SuppressWarnings({"rawtypes","unchecked"})
           Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
       
       // 开始进行数据迁移
       table = newTab;
       if (oldTab != null) {
           // 遍历oldTab中的数据,并迁移到新数组。
           for (int j = 0; j < oldCap; ++j) {
               Node<K,V> e;
               // 如果oldTab数组中j位置数据不为null,进行遍历,并赋值给e,避免直接对oldTab进行操作
               if ((e = oldTab[j]) != null) {
                   oldTab[j] = null;
                   // 如果oldTab的j位置数据没有形成链表,就直接赋值到newTab
                   if (e.next == null)