JDK1.7 版本中 HashMap 多线程下使用可能出现死循环

前提

1.有两个线程同时在对一个 HashMap 进行扩容。
2.线程 1 进行扩容 while 循环,在第一次循环中执行完 e.next = newTable[i] 时时间片用完,此时线程 2 进行扩容且完成了扩容。
扩容代码:

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;
            }
       }
}

线程 2 扩容完成后的容器结构如下图:
扩容

1.线程 1 进行扩容,在第一次循环中执行完 e.next = newTable[i] 时时间片用完,暂停往下执行,此时,线程 1 中的变量结构如下:

e 指向 a,next 指向 bab的 next 都指向 null
2.线程 2 进行扩容,且扩容完成,此时线程 1 看到的原容器已经发生变化,因此 e 和 next 实际指向结构变为:

3.线程 1 继续执行 newTable[i] = e,结构如下图:

4.线程 1 继续执行 e = next,此时 e 和 next 均指向 b如下图:

5.线程 1 再次进入循环,执行 Entry<K,V> next = e.next 此时 next 指向a如下图:

6.线程 1 执行 e.next = newTable[i],newTable[i] 现在已经是 a 因此本次没有结构变化。
7.线程 1 执行 newTable[i] = e,结构如下:

8.线程 1 执行 e = next,结构如下:

9.线程 1 进入下一轮循环,执行 Entry<K,V> next = e.next 此时 next 指向 null 如下图:

10.线程 1 执行 e.next = newTable[i]重点来了,此时 newTable[i] 对应的是 b,因此 e.next 指向了 b,也就是 a.next 指向了 b,出现了环结构,如下图:

11.线程 1 执行 newTable[i] = e 如下图:

12.线程 1 执行 e = next,e 指向 null,如下图:

13.由于 e 指向了 null,因此循环结束,最终扩容后的容器结构如下:

可以看到,新的容器中有环结构,因此在后续使用过程中会出现死循环。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容