正如许多人已经注意到并遇到的HashMap.put
可以在并发使用时进入无限执行循环(请参阅GRIZZLY-1207,JGRP-525,可能HHH-6414,以及所以answer)。
HashMap
明确记录为非线程安全。显然,正确的解决方法是使用特别是Map
,ConncurrentHashMap
的线程安全实现。我对导致无限循环的并发时序更加好奇。我最近使用Java 7 JRE遇到了这个循环,并想了解确切的原因。例如,这是由多个看跌期间同时引起的吗?
查看HashMap.put内部显示HashMap.Entry
包含指向下一个节点的链接(在存储桶中?)。我假设这些链接正在腐蚀以包含循环引用,这导致无限循环。但是,我仍然不明白腐败是如何发生的。
答案 0 :(得分:33)
与许多人的想法相反,multi-threading
和HashMaps
的主要问题不仅仅是一个重复的条目或一个消失的条目...正如你所说,当一个无限循环可能发生时两个或多个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