jdk1.7的HashMap的源码分析参考我之前整理的HashMap,之前也有整理头插法导致的死循环,这里再整理一下。参考连接
扩容的核心源码如下:
void transfer(Entry[] newTable, boolean rehash) {
int newCapacity = newTable.length;
for (Entry e : table) {
while(null != e) {
//1, 获取旧表的下一个元素
Entry 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;
}
}
}
1, 假设旧表的初始长度为2,此时已经在下标为1的位置存放了两个元素,再put第三个元素的时候考虑需要扩容;
2, 此刻有两个线程A,B都进行put操作,线程A先扩容,执行到代码Entry
然后线程B开始执行transfer函数中的while循环,会把原来的table变成一个table(线程B自己的栈中),再写入到内存中。
注意,因为线程A的e指向了key(3), next指向了key(7), 其在线程B rehash后,指向了线程B重组后的链表。我们可以看到链表的顺序被反转了。
3, 线程A被唤醒,继续执行:
总结:
线程A先执行,执行完Entry