【Java】爲何HashMap是線程不安全的及其餘

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

相關文章
相關標籤/搜索