jdk1.7 HashMapの致命的なエラー:循環リスト

「致命的なエラー」でjdk1.7のHashMap:循環リスト

図jdk1.7のHashMap構成。

jdk1.7は+リンクリスト構造の配列です

jdk1.7バージョンでは、2つの大きな問題が存在します

  1. ケースは、第1の補間サイクル鎖をもたらします

  2. リストが長すぎる、それが減少し、効率の問い合わせにつながります

jdk1.8のために最適化されたjdk1.8バージョン

  1. 補間を使用してテール、除去は、円形のリストを発生します
  2. リストが長すぎるの後、赤黒木に、クエリの効率を向上させます

私は、特にブログの別の記事を参照してください。HashMapのそれを:あなたは本当にメーカーが質問に直面している知っていますか?

円形リストを作成

一方、マルチスレッドputの呼び出し同時に場合、resize循環リストにつながる可能性がある操作をこのように取り戻すための時間を作り、生成され、それが無限ループになります。以下、詳細どのように循環リスト形式。

リサイズ機能

アレイの拡張機能は、主な機能は、拡張後の新しい配列を作成することで、呼び出すtransfer関数は新しい配列に配列内の古い要素を移行します

void resize(int newCapacity)
{
    Entry[] oldTable = table;
    int oldCapacity = oldTable.length;
    ......
    //创建一个新的Hash Table
    Entry[] newTable = new Entry[newCapacity];
    //将Old Hash Table上的数据迁移到New Hash Table上
    transfer(newTable);
    table = newTable;
    threshold = (int)(newCapacity * loadFactor);
}

伝達関数

転送ロジックは、古いアレイを横断し、実際に簡単であり、古いによってアレイ素子ヘッダ補間方法、アレイ内の新たな問題嘘への移行に対応する位置のヘッド補間

void transfer(Entry[] newTable)
{
    //src旧数组
    Entry[] src = table;
    int newCapacity = newTable.length;
 
    for (int j = 0; j < src.length; j++) {
        Entry<K,V> e = src[j];
        if (e != null) {
            src[j] = null;
            do {
                Entry<K,V> next = e.next; 
                int i = indexFor(e.hash, newCapacity);
                e.next = newTable[i];
                newTable[i] = e;
                e = next;
            } while (e != null);//由于是链表,所以有个循环过程
        }
    }
}

static int indexFor(int h, int length){
    return h&(length-1);
}

ここでは実用的な例です

//下面详细解释需要用到这部分代码,所以先标号,将一下代码分为五个步骤
do {
	1、Entry<K,V> next = e.next; 
	2int i = indexFor(e.hash, newCapacity);
	3、e.next = newTab[i];
	4、newTable[i] = e;
	5、e= next;
} while(e != null)
  • 始めます H A S 時間 M A P HashMapの 容量が2に設定され、閾値がロードされます 2 * 0.75 = 1 2 * 0.75 = 1

  • スレッド T 2 T_2 そして、スレッド T 1 T_1 閾値が1であるので、必要にコールするよう一方、要素を挿入するresize機能を拡張するための操作を

  • スレッド T 1 T_1 まず、コードをブロックしEntry<K,V> next = e.next;たスレッドの後、 T 2 T_2 操作の拡張を実行した後

  • スレッドの後 T 1 T_1 サイクルの完了後、引き続き、目を覚まします

    始めます E 3 E \ rightarrow3 n個 E バツ トン 7 次の\ rightarrow7 、次のコードの実装、 E 7 電子\ RIGHTARROW 7 n個 E バツ トン 3 次の\ rightarrow3

    2int i = indexFor(e.hash, newCapacity);
    3、e.next = newTab[i];
    4、newTable[i] = e;
    5、e= next;
    1、Entry<K,V> next = e.next; 
    

  • スレッド T 1 T_1 第二サイクルの実施後

    始めます E 7 電子\ RIGHTARROW 7 n個 E バツ トン 3 次の\ RIGHTARROW 3 、次のコードが実行され、$ E \ rightarrow3 $、 n個 E バツ トン n個 リットル リットル 次の\ RIGHTARROWはnull

    2int i = indexFor(e.hash, newCapacity);
    3、e.next = newTab[i];
    4、newTable[i] = e;
    5、e= next;
    1、Entry<K,V> next = e.next; 
    

  • エンドレスループを形成する第3のサイクルの実行スレッドT1、後

    始めます E 3 E \ RIGHTARROW 3 n個 E バツ トン n個 リットル リットル 次の\ RIGHTARROWはnull 、次のコードを、 E n個 リットル リットル 電子\ RIGHTARROWはnull

    2int i = indexFor(e.hash, newCapacity);
    3、e.next = newTab[i];
    4、newTable[i] = e;
    5、e= next;
    1、Entry<K,V> next = e.next; 
    

あなたは無限ループに入る(11)、11%4 = 3を実行した場合

リファレンス

JDK1.7 HashMapのは、循環リストにつながります

184元記事公開 ウォンの賞賛220 ビューに14万+を

おすすめ

転載: blog.csdn.net/zycxnanwang/article/details/105415550