26

多くの人が指摘し、HashMap.put同時に使用すると無限実行ループに陥る可能性があることに遭遇しました(GRIZZLY-1207JGRP-525、おそらくHHH-6414、および this SO answerを参照)。

HashMapスレッドセーフではないことが明確に文書化されています。明らかに、正しい修正は、特に のスレッドセーフな実装を使用することMapですConncurrentHashMap。無限ループを引き起こす同時タイミングについてもっと興味があります。最近、Java 7 JRE でこのループに遭遇しました。正確な原因を理解したいと思います。たとえば、これは同時に複数のプットが原因ですか?

HashMap.putの中を見るHashMap.Entryと、次のノード (バケット内?) へのリンクが含まれていることがわかります。これらのリンクが破損して循環参照が含まれているため、無限ループが発生していると思います。ただし、その破損がどのように発生しているのかはまだ正確にはわかりません。

4

1 に答える 1

34

多くの人が考えているのとは反対に、 と の主な問題は、エントリの重複や消失だけmulti-threadingHashMapsはありません...おっしゃったように、2 つまたは複数がThreads同時に のサイズを変更しようとすると、無限ループが発生する可能性がありますHashMap

HashMap のサイズが特定のしきい値を超えると、複数のスレッドが同時にサイズを変更しようとする可能性があり、運が良ければ (すでにコードを本番環境にデプロイしている場合)、それらは永遠に続きます...

この問題は、void resize(int newCapacity);void transfer(Entry[] newTable);の実装方法が原因で発生します。openjdk のソース コードを自分で確認できます。運が悪かったり、タイミングが良かったり、エントリが逆になったり (このデータ構造では順序付けは必要ありません)、スレッドが進行している間に誤って相互に参照することになるwhile(e != null)...

自分で説明をしようとすることもできますが、Paul Tymaの投稿 (とにかく彼よりうまくやることはできません) の功績を認めたいと思います。数ヶ月前に就職した...

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

ポールが言うように、このレースを表現するのに最適な言葉はコンディションです:beautiful

于 2012-12-04T04:28:02.543 に答える