1.8之前的HashMap线程不安全,包含循环链表的问题,get()时候会造成死循环cpu爆满。原因是1.8之前采用的头插法;1.8之后采用尾插法。
1.8 resize()
final Node<K,V>[] resize() {Node<K,V>[] oldTab = table;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;}// 新容器size扩大一倍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 thresholdnewCap = oldThr;else { // zero initial threshold signifies using defaultsnewCap = 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"})// 开启一个新数组,size为原来两倍Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];// 指向新的tabletable = newTab;if (oldTab != null) {// 遍历老的数组for (int j = 0; j < oldCap; ++j) {Node<K,V> e;// 遍历元素链表if ((e = oldTab[j]) != null) {oldTab[j] = null;if (e.next == null)// 单节点直接用&定位,容量是1000 变成 10000,则&之后要么在原来位置,要么是原来位置*2newTab[e.hash & (newCap - 1)] = e;else if (e instanceof TreeNode)// 如果改节点已经变成一颗树了,在树中插入((TreeNode<K,V>)e).split(this, newTab, j, oldCap);else { // preserve order// 新表size是原来一倍,所以出现高位和低位,所以拆出来两条链表了,每个链表都维护头和尾Node<K,V> loHead = null, loTail = null;Node<K,V> hiHead = null, hiTail = null;Node<K,V> next;do {next = e.next;if ((e.hash & oldCap) == 0) {if (loTail == null)loHead = e;elseloTail.next = e;loTail = e;}else {if (hiTail == null)hiHead = e;elsehiTail.next = e;hiTail = e;}} while ((e = next) != null);if (loTail != null) {loTail.next = null;newTab[j] = loHead;}if (hiTail != null) {hiTail.next = null;newTab[j + oldCap] = hiHead;}}}}}return newTab;}
