HashMap扩容死锁问题分析(JDK1.7)
//JDK1.7扩容源代码
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 {
Entry<K,V> next = e.next;
//重新计算hash值
int i = indexFor(e.hash, newCapacity);
e.next = newTable[i];
newTable[i] = e;
e = next;
} while (e != null);
}
}
}
JDK1.7单线程扩容详解:
- 假设A、N、M的hash值相同,发生hash碰撞,都放到3这个位置上(此处省略M的插入过程)
-
JDK1.7是采用头插法进行构建链表的,put后的结果如下:
需要扩容时:
-
第一次do,while循环
-
第二次do,while循环
-
第三次do,while循环
JDK1.7多线程扩容详解:
- 假设T1在Entry<K,V> next = e.next;这行失去了CPU使用权。
-
T2继续执行扩容(T2的扩容过程与上诉单线程类似,不同的是T1会保持指针的引用),结果如下:
-
T1开始执行:
-
T1第一次循环后的数据结构
-
T1第二次循环后的数据结构
-
T1第三次循环后的数据结构
- 当e=null时,T1扩容结束。此时我们可以看出,链表已经成为一个环形。
- 下次在put数据时,会循环链表查找是否有重复数据。就会形成死循环。