HashMap在多线程下面出现死循环,这种情况有点难模拟,千万别在生成环境出现,一旦出现那就等着哭吧。
废话不多说不知道hashmap 如何扩容的先看下源码可能好理解点。
void resize(int newCapacity) {
Entry[] oldTable = table;
int oldCapacity = oldTable.length;
if (oldCapacity == MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return;
}
Entry[] newTable = new Entry[newCapacity];
transfer(newTable);
table = newTable;
threshold = (int) (newCapacity * loadFactor);
}
//此方法就是 hashMap 将数据放到新的扩容之后的数组,方法没啥问题,完全正确无误。
void transfer(Entry[] newTable) {
Entry[] src = table;
int newCapacity = newTable.length;
for (int j = 0; j < src.length; j++) {
Entry<K, V> e = src[j];
if (e != null) {
src[j] = null;
do {
//过程(1)
Entry<K, V> next = e.next;
int i = indexFor(e.hash, newCapacity);
e.next = newTable[i];
newTable[i] = e;
e = next;
} while (e != null);
}
}
}
在多线程情况下,情况就不一样了。模拟一种情况:
假设现在HashMap 的table 长度为2 ,因子为1 如下图
现有线程P1 、P2
当P1线程执行到 过程(1)下面的时候
此时 e =a1 ,next = a2 P2 进入执行了并且执行完毕
当前新的结构为
再执行P1 此时得到的新数组索引和P2 是一样。
e.next =newTable[i] 即为 a2 (a2.next =a1)
newTable[i] = e 即为 a1 数组结构变为
e=next 即为 a2 ;
第二次循环的时候
Entry<K, V> next = e.next 即为a1
e.next = newTable[i]; 即为 a1 (a1.next = a2)
newTable[i] = e 即为 a2 数据结构变为
e=next 即为 a1 ;
第三次的循环的时候
Entry<K, V> next = e.next 即为a2
就形成了回环了。
就成了死循环。
在多线程循环下不要使用hashmap 。