1. threshold HashMap扩容阈值
capacity(容量) * loadFactor(加载因子),如果new对象没有传入容量,则阈值大小为0,如果传入容量,则通过tableSizeFor 设置为大于容量的最小的2的幂次。
2. 扩容源码
1 final Node<K,V>[] resize() { 2 Node<K,V>[] oldTab = table; 3 int oldCap = (oldTab == null) ? 0 : oldTab.length; 4 int oldThr = threshold; 5 int newCap, newThr = 0; 6 //table 不为空 7 if (oldCap > 0) { 8 //无法扩容 9 if (oldCap >= MAXIMUM_CAPACITY) { 10 threshold = Integer.MAX_VALUE; 11 return oldTab; 12 }//扩容2倍 13 else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY && 14 oldCap >= DEFAULT_INITIAL_CAPACITY) 15 newThr = oldThr << 1; // double threshold 16 } 17 //以下table 为空情况 18 else if (oldThr > 0) //table 为空情况且 设置了初始大小initial capacity,新容量为阈值大小 19 newCap = oldThr; 20 else { //table 为空情况且没有设置初始容量,采用默认值初始化 21 newCap = DEFAULT_INITIAL_CAPACITY; 22 newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY); 23 } 24 if (newThr == 0) { //阈值 25 float ft = (float)newCap * loadFactor; 26 newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ? 27 (int)ft : Integer.MAX_VALUE); 28 } 29 threshold = newThr; 30 @SuppressWarnings({"rawtypes","unchecked"}) 31 Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap]; 32 table = newTab; 33 if (oldTab != null) { 34 for (int j = 0; j < oldCap; ++j) { 35 Node<K,V> e; 36 if ((e = oldTab[j]) != null) { 37 oldTab[j] = null; 38 //只有一个节点,直接放入新table中 39 if (e.next == null) 40 newTab[e.hash & (newCap - 1)] = e; 41 //为红黑树,则对树进行拆分 42 else if (e instanceof TreeNode) 43 ((TreeNode<K,V>)e).split(this, newTab, j, oldCap); 44 //链表拆分,原链表拆分成2个链表newTab[j],newTab[j + oldCap]为2个链表的头结点 45 else { // preserve order 46 Node<K,V> loHead = null, loTail = null; 47 Node<K,V> hiHead = null, hiTail = null; 48 Node<K,V> next; 49 do { 50 next = e.next; 51 if ((e.hash & oldCap) == 0) { 52 if (loTail == null) 53 loHead = e; 54 else 55 loTail.next = e; 56 loTail = e; 57 } 58 else { 59 if (hiTail == null) 60 hiHead = e; 61 else 62 hiTail.next = e; 63 hiTail = e; 64 } 65 } while ((e = next) != null); 66 if (loTail != null) { 67 loTail.next = null; 68 newTab[j] = loHead; 69 } 70 if (hiTail != null) { 71 hiTail.next = null; 72 newTab[j + oldCap] = hiHead; 73 } 74 } 75 } 76 } 77 } 78 return newTab; 79 }
3. 由于扩容是比较耗性能的操作,所以一开始就尽量预测好初始容量,以减少扩容带来的性能损耗,比如 HashMap(1000),考虑变更为 new HashMap(1024) 但是不是最佳,因为加载因子默认0.75,即
0.75*1000<1000,阈值小于1000,故最好设置为new HashMap(2048),就能避免resize