jdk 7 hashMapが安全でないことから生じる疑问、JMMの大人を熟知して解答して下さい

4903 ワード

jdk 8以前の拡張操作では、同時でチェーンテーブルにループが形成されます.重要なのは、transfer法でヘッドプラグ法を使用して新しい値をチェーンテーブルヘッダに挿入することです.
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; // , next ,             
            if (rehash) {
                e.hash = null == e.key ? 0 : hash(e.key);
            }
            int i = indexFor(e.hash, newCapacity);                 //  null, e.next = null           
            e.next = newTable[i];
            newTable[i] = e; //                 
            e = next;        //             
        } // while        
    }
}

多くの解釈を見て(e 1.next=e 2と仮定し、再びhashした後も同じバケツの中にある):1.スレッドAはnext=e 1を取得する.nextは、次のノードe 2を取得してから掛けます.このときe=e 1,next=e 2となる.スレッドBがチェーンテーブルの拡張に成功したときe 2はチェーンヘッドにあり、e 2.next = e1. 3.この時点でスレッドAが実行され続けると、next=e 2がe!=null、whileは終了せず、再び論理を実行する、このときe 2.next=e 1(スレッドBによる結果)は変数e=next=e.nextすなわちe 2をもたらす.next=e 1である、eは再びe 1を指し、このときバケツ中のe 2はチェーンヘッド、e 2にある.next = e1 4.next=e 1であるため、e=e 1となり、論理を実行し続ける.next=null、サイクルは終了するが、e 1はチェーンヘッドに入れられ、バケツ中のe 1となる.next=e 2、第3のステップでe 2.next=e 1は,このように閉ループとなる.
ここで質問があります.黄色のハイライト位置、e 2.next=e 1(スレッドBによる結果)は変数e=next=e.nextすなわちe 2をもたらす.next=e 1である、eは再びe 1を指す:スレッドBが終了した後、どのようにしてワークメモリをメインメモリに戻すか2:スレッドAはなぜメインメモリe 2を読み取るのか2.next=e 1は、自分のワークメモリe 2ではない.next =null?
いくつかの可視性の実験によって発見された.
データを読み込む前に、sleepメソッドを呼び出すもSystemを呼び出すも構わない.out.println()メソッド、さらにはnewの配列、またはhttpリクエストを送信すると、iはメインメモリのデータをワークメモリにリフレッシュします.根拠のない言い方は、次のとおりです.
これらの方法の1つの共通点は,これらの方法は時間がかかるが,CPU計算の占有量が少ないことである.メモリ割り当てをしているのではなく、IOをしているので、CPUタイムスライスを消費していますが、CPUは暇です.従来、JVM大神たちの毎日の丧(乾)心(得)病(ドリフト)狂(亮)の努力を通じて、JVMは现在のハードウェアレベルに対してすでに大幅な最適化を行い、基本的にはワークメモリとメインメモリのタイムリーな同期を保障し、volitaleをデフォルトで使用したことに相当する.しかし、最大限です.CPUリソースがずっと占有されている間、ワークメモリとメインメモリの間の同期、つまり変数の可視性はそんなにタイムリーではありません!
しかし私はやはりJMMの大きい人がこの疑問に答えることができることを望みます