一尘不染

调整大小时在多线程环境中的Hashmap

java

我正在学习一个教程,它基本上解释了在多线程环境中调整Hashmap大小时发生争用情况的原因:

在Java中,如果同时发现两个线程,则HashMap需要调整大小,并且它们都尝试调整大小。在Java中调整HashMap的大小的过程中,存储在链表中的存储桶中的元素在迁移到新存储桶的过程中顺序颠倒,因为Java
HashMap不会在尾部附加新元素,而是在头部附加新元素。避免横越尾巴。如果发生比赛条件,那么您将陷入无限循环

阅读此书后,我有两个问题:

  1. 为什么每个存储桶的链表顺序颠倒?
  2. 我可以看到可能存在竞争条件,但看不到无限循环是如何来的?是因为一个线程可能将元素的头部附加到尾部,而另一个则以相反的顺序进行呢?

请帮我澄清一下,万分感谢!


阅读 271

收藏
2020-12-03

共1个答案

一尘不染

实际上,至少有一种与 重新哈希处理 有关的竞赛条件。查看以下代码片段(来自Sun JDK7):

boolean oldAltHashing = this.useAltHashing;
this.useAltHashing |= sun.misc.VM.isBooted() && (this.newCapacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD);
boolean rehash = oldAltHashing ^ this.useAltHashing;
transfer(newTable, rehash);
this.table = newTable;

在这里,线程T1最终以rehash = true线程T2最终rehash = false(假设T1已更改的值this.useAltHashing)是可能的。

现在,猜猜哪个线程将编写this.table-您也不知道可以。因此,是否获得一致的内部状态是一个运气问题。

无论如何,正如我在 设计 评论中提到的那样 ,不应在多线程环境中使用HashMap 。不起作用。因为这个原因或其他原因。以上只是为什么
不应该违反合同的 一个例子

2020-12-03