JDK1.7 HashMap扩容:多线程下的死循环和丢失
2018-05-20 本文已影响295人
xiaoyiyiyo
多线程情况下,HashMap扩容可能会形成死循环情况,或者丢失值。
假设:
三个Entity,rehash后key值分别为3、5、7。
如图:
![](https://img.haomeiwen.com/i10232085/2d0512c0733635ac.png)
JDK 1.7 HashMap扩容时关键代码:
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; // 第5行 关键步骤1
if (rehash) {
e.hash = null == e.key ? 0 : hash(e.key);
}
int i = indexFor(e.hash, newCapacity);
e.next = newTable[i]; //关键步骤2
newTable[i] = e; //关键步骤3
e = next; //关键步骤4
}
}
}
请记住上面的4个关键步骤!!!
死循环:
B第一次while循环:
![](https://img.haomeiwen.com/i10232085/4ee4a11a015e5c93.png)
B第二次while循环:
![](https://img.haomeiwen.com/i10232085/cd8d65e5438aa9b8.png)
B第三次while循环:
![](https://img.haomeiwen.com/i10232085/48c2994d36b8a0b4.png)
线程B执行完的状态,A恢复执行:
![](https://img.haomeiwen.com/i10232085/cd8636fb7ee3a7f6.png)
线程A开始执行的状态:
![](https://img.haomeiwen.com/i10232085/564a07f5d92f8553.png)
线程A开始执行第6行,第一次while循环:
![](https://img.haomeiwen.com/i10232085/1f2980a6e4511613.png)
A第二次while循环:
![](https://img.haomeiwen.com/i10232085/816c4092634a0a58.png)
A第三次while循环:
![](https://img.haomeiwen.com/i10232085/bbc82753fd96f453.png)
线程A执行完,已形成死循环。红线。
值丢失:
更换下三个Entity的顺序,注意如图:
![](https://img.haomeiwen.com/i10232085/ec7f80b95a61fee2.png)
线程A开始执行:
![](https://img.haomeiwen.com/i10232085/17f683db91b6715c.png)
线程A第二次while循环:
![](https://img.haomeiwen.com/i10232085/8126504ca12e942f.png)