JDK-8299339 : HashMap merge and compute methods can cause odd resizing pathologies
贴一下去年发现的 Bug,嘿嘿。
导致 Bug 的示例代码如下:
1 | public class Main { |
Java Bug DataBase 链接,里面比较详细的讨论了发生的问题,由于当时急着发出去,我的评论有点乱,而且是中文翻译为英文的,有点拉。
今天重新回顾一下 Bug,顺便简单解释一下。上述代码的输出为 2,期望输出是 2 和 1(顺序不重要)。问题在于,在两次 merge
之后,map
包含的元素数量 2 已经超过扩容阈值 1,下一次扩容发生在迭代中,导致不正确的输出。具体来说,在 resize
方法中,有 oldTab[j] = null;
操作,即转移元素到新数组时,会将旧数组的所有元素置为 null
,从而旧数组的迭代器扫描不到剩余的元素。总的来说,即使在遍历的过程中,没有发生结构性的修改,在特定情况下使用 merge
方法修改 HashMap
依然会导致问题。特定情况是指,在遍历之前 HashMap
的包含的元素数量超过扩容阈值,然后在遍历的过程中使用 merge
方法。
ORACLE 的内部人员首先说明,由于调用 Map
上的方法可能产生破坏迭代的副作用,所以不建议在迭代的过程中调用 Map
上的方法,特别是具有副作用的方法,建议重写代码避免这种情况。然后提到 merge
方法确实有问题,即元素数量超过阈值也没有立即扩容,它和 put
方法的实现不同。评论中还列出其他具有类似副作用的方法,以及其他产生副作用的情况,详细看链接。
JDK-8299339 : HashMap merge and compute methods can cause odd resizing pathologies