HashMap循環リンクリストの問題を明確に理解する

今日のこのトピックは、後で更新されるConcurrentHashMapを学習するための基礎を築くことです。

jdk1.7では、HashMapが配列(バケット)+リンクリストで構成される構造であることは誰もが知っているので、今日は、同時実行の場合のHashMapのデッドリンクの問題を見てみましょう。

分析する

容量が設定されたしきい値(0.75f)に達すると、HashMapが拡張されることがわかっているため、拡張は移行の問題に合わせて設計されており、1.7のHashMapは挿入時にヘッド挿入方式を使用します。

picture.png

void transfer(Entry[] newTable, boolean rehash) {
    int newCapacity = newTable.length;
    for (Entry<K,V> e : table) {
        while(null != e) {
            Entry<K,V> next = e.next;//T1执行到这里时间片到期退出
            if (rehash) {
                e.hash = null == e.key ? 0 : hash(e.key);
            }
            int i = indexFor(e.hash, newCapacity);
            e.next = newTable[i];
            newTable[i] = e;
            e = next;
        }
    }
}
复制代码

たとえば、Entry1とEntry2に示すように、2つのスレッドT1とT2が同時に結合しています。しきい値に達すると、2つのスレッドが同時に拡張されます(ここには2つのnewTableがあります)。 eとT1.nextは次のとおりです。図に示すように、タイムスライスが期限切れになると、CPU実行リソースが放棄され、図の右側に示すように、T2がサイズ変更を完了します。このとき、T1スレッド目を覚ますと、T1.eとT1.nextが図の右側に表示されていることがわかります。彼らはコードを実行し続けます

e.next = newTable[i];
newTable[i] = e;
复制代码

OK、ヘッド挿入メソッド、2番目のnewTableに配置します。e.next= null、newTable [i] = e

picture.png

次に、ループe = Entry2、next=Entry1。その後、プラグインを続けると、このようになります。

picture.png最後のループ、e = Entry1、next=null。プラグを差し込んでください。

picture.pngここにnewTableリングリンクが形成されています。プログラムがキーを検索すると、常に抜け出せない場合があり、CPUリソースの使用率が100%になります。

要約する

したがって、主な理由は、ヘッド挿入方式が使用され、並行条件下でプログラムの無限ループが発生し、キー(循環リンクリストの背後)が見つからないことです。そのため、1.8のHashMapが改善され、無限ループを発生させずに順序を確保するためにテール挿入方式が使用されています。結局のところ、マルチスレッドの場合、無限ループは発生しませんが、誤ったセマンティクスが発生します。

おすすめ

転載: juejin.im/post/7086372830807326733