解释导致HashMap.put()执行无限循环的时间

时间:2012-12-04 03:57:05

标签: java concurrency thread-safety hashmap

正如许多人已经注意到并遇到的HashMap.put可以在并发使用时进入无限执行循环(请参阅GRIZZLY-1207JGRP-525,可能HHH-6414,以及所以answer)。

HashMap明确记录为非线程安全。显然,正确的解决方法是使用特别是MapConncurrentHashMap的线程安全实现。我对导致无限循环的并发时序更加好奇。我最近使用Java 7 JRE遇到了这个循环,并想了解确切的原因。例如,这是由多个看跌期间同时引起的吗?

查看HashMap.put内部显示HashMap.Entry包含指向下一个节点的链接(在存储桶中?)。我假设这些链接正在腐蚀以包含循环引用,这导致无限循环。但是,我仍然不明白腐败是如何发生的。

1 个答案:

答案 0 :(得分:33)

与许多人的想法相反,multi-threadingHashMaps的主要问题不仅仅是一个重复的条目或一个消失的条目...正如你所说,当一个无限循环可能发生时两个或多个Threads同时决定调整HashMap的大小。

如果HashMap的大小超过给定的阈值,多个线程最终可能会同时尝试调整它的大小,如果我们足够幸运(您已经在生产中部署了代码),它们将永远继续...

问题是由void resize(int newCapacity);void transfer(Entry[] newTable);的实施方式引起的,您可以自己查看openjdk source code。糟糕的运气,良好的时机,相反的条目(此数据结构中不需要排序)以及最终在线程继续进行时错误地引用彼此while(e != null) ...

虽然我可以尝试自己给你一个解释,但我想赞扬Paul Tyma的帖子(我无论如何都做得不好),在那里我第一次了解这是如何工作的几个月前我没有被雇用的原因......

http://mailinator.blogspot.com/2009/06/beautiful-race-condition.html

正如保罗所说,描述这场比赛的最佳词语是:beautiful