【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

相关文章
相关标签/搜索