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->1;
3、線程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:看不懂純屬我寫的不好