rehash問題小記?

1、爲什麼hashmap中length是16,resize要是2的冪次的問題

**hashcode(key)&(length-1):16-1爲二進制的1111,進行與運算的時候能夠較爲散列地計算key的index值,那爲啥resize要2的次冪呢,道理是一樣的,擴大2的一次方,length-1就是11111,進行與運算一看就知道。

2 高併發下的rehash?

**javadoc中關於hashmap的一段描述如下:
HashMap底層是一個Entry數組,當發生hash衝突的時候,hashmap是採用鏈表的方式來解決的,在對應的數組位置存放鏈表的頭結點。對鏈表而言,新加入的節點會從頭結點加入。
此實現不是同步的。如果多個線程同時訪問一個哈希映射,而其中至少一個線程從結構上修改了該映射,則它必須 保持外部同步。(結構上的修改是指添加或刪除一個或多個映射關係的任何操作;僅改變與實例已經包含的鍵關聯的值不是結構上的修改。)

造成多線程下rehash的不安全問題純粹是下面這個函數

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;
                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;
            }
        }
}
rehash前:table[0]->1->2
1、有兩個線程A,B,就是線程A在執行到Entry<K,V> next = e.next;時候,停住,把e->1和next->2指向的內容保存起來(這一保存就出事了);
2、線程B正常從頭執行到尾,執行完會,使用的是頭插法,原來1->2,變成了2->13、線程A開始復活,next和e還保留着(而且還是1->2這樣指着),繼續操作下去,
    (內存中e->1和next->2 )     newTable[3]-> 1->null  

    (內存中e->2和next->1)      newTable[3]-> 2->1->null  

    (內存中e->1和next->null)  newTable[3]->1->2&& 2->1 

    然後next變null,結束;

使用頭插法,插插插,插出了個環,如果這個位置假設是3,map.get(3),就會進入死循環,一直在裏面繞。


end:看不懂純屬我寫的不好

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章