1. resize引發的死循環java
java中HashMap初始容量是16;每次插入前須要判斷是超過thredhold,若是超過則須要擴容。擴容過程須要rehash,即從新計算每一個key的hash值並放在合適的位置,是一個開銷很大的操做。實現是transfer()方法,代碼以下。數組
void transfer(Entry[] newTable, boolean rehash) { int newCapacity = newTable.length; for (Entry<K,V> e : table) { while(null != e) { Entry<K,V> next = e.next; if (rehash) { e.hash = null == e.key ? 0 : hash(e.key); } int i = indexFor(e.hash, newCapacity); e.next = newTable[i]; newTable[i] = e; e = next; } } }
以上代碼實現的操做是:遍歷Entry數組,爲Entry指向的鏈表的每一個元素計算其在擴容後的位置,並把當前鏈表按頭插法(注意最後三行代碼)插入新表。頭插法會形成逆序,好比老表a->b->c的鏈表在新表中是c->b->a。若是兩個線程同時更新,可能會形成a->b且b->a的狀況,新的哈希表中就存在一個死循環。多線程
2. ConcurrentModificationExceptionspa
迭代器使用過程當中,其餘線程修改了map,則拋出異常。這是我寫多線程時遇到過的問題。被稱爲fail-fast策略。線程
3. 爲何使用String(Integer)作keycode
a.重寫過equals()和hashcode();有理由相信官方重寫的hashcode碰撞更低,在使用HashMap時效率更高。對象
b.這些類是final的。意味着equals()和hashcode()不會重寫;若是在put()和get()時,對象的hashcode改變,則不能得到目標對象ci