ソースは、HashMapのスレッド安全性の問題を解決します

    私たちはしばしばインタビューで、この問題が発生します。

                  Q:HashMapのは、スレッドセーフですか?

                  A:いいえ

                  Q:なぜ?

                  A:マルチスレッド化問題を引き起こす無限ループの場合のため、ハッシュマップの拡張

jdk1.7とjdk1.8でハッシュマップはjdk1.8には当てはまらない間だけ、上記の問題は、jdk1.7に発生しますが、同じではありませんので、上記の答えは、正確ではありません。

今、私たちは、ソースコードを見てマルチスレッドの拡張の場合はハッシュマップでjdk1.7は無限ループになりますなぜ、我々はソースを直接見:

エレメントの方法はハッシュマップに配置された私達の簡単な説明は、閾値は、方法は、拡張リサイズ、2倍の長さを入力したときの要素の数ハッシュマップが閾値に達したときに決定addEntryを有します。サイズ変更では、まずアレイNEWTABLEエントリを作成し、長さnewCapacityは、新しいアレイNEWTABLEに、アレイ内のオリジナルの要素を変換するために、転送方法に入り、そして今はfacie転送方法に焦点を当てて見ることができます。

この方法は、ロングコードのわずか15行の合計ではありませんが、それは無限ループを引き起こす重要な場所です。:以下のように、> 4 - コードレッドボックスHashMapのは、死のサイクルの原因で、我々は今、元の配列の最初の要素はリスト2であることを前提としてい

    2 ---> 4  

 

今、私たちは、それは要素が何であるかを横断しながら、私たちは初めて見て、仮定が偽の焼き直しに変換する方法が何であるかを再現します:

Eは、要素は、図1に見ることができるある。2、e.next素子4、及びNEWTABLE新しいアレイ、NEWTABLE [I]がNULLであるので、最初のパスの後端が、我々は新しいアレイの記憶素子を見ながら状況:

   2 --->はnull      

 

私たちは今、第二のパスながら見て:

要素と要素2及び4は、元の配列内の同じ位置にあるので、そのための図上記Eは、その素子4から分かるe.hash値が同じであるので、計算添字iが同じです、 NEWTABLEので、[i]は最後の要素2です。従ってe.next = 2、NEWTABLE [I] = 4は、 ループの終わりがNULLである次、ダウンし続けます。私たちは、の場合に格納された新しい配列の要素を見て続行します。

   4 ---> 2      

 

要素の上に見ることができるリストがあるため、反転された同じ位置の複数の要素は、それが新しい方法に第1の補間要素を使用する場合は、膨張時のときのHashMap jdk1.7変換素子配列の要素である、常に元の要素の先頭に挿入されます。

今、私たちは、Aは、B2スレッド後、592ラインの実装でスレッド最初のサイクルが終了するが、ハングアップされているとします。> 4、4 - - 無限ループの状況> 2今4点2を終了し、2サイクルにわたって実行されるスレッドBが来る、Bは、Aが続く、2登場しました。

私たちは、J探し続けマルチスレッドの場合の動作ソースdk1.8のハッシュマップの拡大を:

いくつかの単語の男は言った直接リサイズ方法を探して、:

サイズ変更方法を表示すると、突然、私はポイントはので、この書き込み、最適化することができます感じたリサイズの最適化を推論が正確ではないが、全体的な思考プロセスが完全で、興味のある缶の外観ですが、。

ハッシュ値が同じ場所はほとんどの場合と異なっているので、唯一e.hash&oldCap 2例が存在するであろう、0に等しく、0に等しいので、loHead、loTailとhiHeadを使用しない、hiTailは、4つの変数を区別する一方loTail.next = NULL;及びhiTail.next = NULL;これらの効果は、データの重複を避けるために、ライン2と同じです。

コードは見て私たちはライン722から726と736から739行に焦点を当て、非常に長い、または2 - > 4は、我々はそれで2倍のデータ変換を見て、最初のサイクル:

 

LoTail最初のサイクルはヌルであり、そしてようloHead loTail素子2は、第二サイクル等しいです。

したがって、> 4 -第二サイクルが完了した後、アレイNEWTAB [J]に新たな要素が元のシーケンス2のままで見ることができる拡張はマルチスレッド無限ループの場合には発生しない場合であっても。しかし、HashMapの中jdk1.8まだスレッドセーフではありません、データカバレッジが発生する可能性があり、我々はソースコードを見て:

、我々は、ルック行630と631行、630行を集中し、631行は、n-1ハッシュプレス低い(すなわち、モジュロ)マーク形成要素で見ることができ、被写体が空であるか否かを、下位要素が決定さ削除します配列要素にタブは空になります。

今、我々は、Aは、ハッシュマップに配置されたB2糸要素は、あるスレッドと仮定iが1、値= 4 = Bとのスレッドが、エレメント列630を実行するために中断され= iが1、値= 5つの 要素は、端部に実行されます。スレッドは、実行時間タブ[1] = 4、両端を継続します。そのような要素値= 5が上書きされます。

要約:

            Q:HashMapのは、スレッドセーフですか?

            A:いいえ

            Q:なぜ?

            理由:jdk1.7マルチスレッド拡張の場合にはハッシュマップ、に起因するヘッドが無限ループの問題を引き起こすことができるように、補間を使用してデータ変換のリストに。jdk1.8に元のリストに新しいアレイが無限ループを引き起こさないに直接データを最適化するが、マルチスレッド原因データカバレッジの場合にしました

 

 

发布了25 篇原创文章 · 获赞 51 · 访问量 2万+

おすすめ

転載: blog.csdn.net/Royal_lr/article/details/103185683