目錄
1.擴容形成環路
2.get(key)操作死迴圈
在put元素超過負載閾值時會觸發hashmap的擴容resize操作,乙個桶的鍊錶會重新雜湊到新錶中,
/**
* put 插入元素之後,負載超過閾值,觸發resize方法擴容
*/
void addentry(int hash, k key, v value, int bucketindex)
/**
* resize(),transfer把舊表中的元素新增到新錶中
*/
void resize(int newcapacity)
entry newtable = new entry[newcapacity]; // 建立新錶
transfer(newtable);
table = newtable;
threshold = (int)(newcapacity * loadfactor);
} void transfer(entry newtable, boolean rehash)
int i = indexfor(e.hash, newcapacity);
// 插入到桶中鏈頭
e.next = newtable[i];
newtable[i] = e; // 放入桶中煉表頭
e = next; // 鏈向原表頭
} // while}}
操作**釋
map.put(7,"b");插入鏈頭如圖
有兩個桶的table,
threshold=cap*default_load_factor=1
第二次put就會觸發擴容
併發擴容,
如果執行緒b在拷貝新錶第一行已經拿到next節點後發生切換,
執行緒a正常拷貝結束,插入隊頭
執行緒b切回繼續拷貝,就會形成環路
且由於可見性問題,擴容操作的遍歷可以結束,因為next的next在此時的快取記憶體裡是null。
獲取15時,會落在tab[2]裡,會遍歷鍊錶,鍊錶中沒有命中,就會一直遍歷下去(回頭路)!
hashmap在get操作一直在搶占cpu,按道理get操作是平均o(1)的,不太會造成這種現象
那是因為get操作需要遍歷拉鍊後的鍊錶,鍊錶如果key不命中,就一直迴圈下去。
JDK1 7的HashMap死迴圈
為什麼在jdk1.7多執行緒情況下會很容易出現hashmap死迴圈,這個還是要根據它採取的擴容策略來看,它的擴容策略是頭插法,因此會導致這樣的問題。在jdk1.8改進為尾插法,但並不意味著尾插法能適應多執行緒併發的場景,我認為其最主要的考慮就是頭插法在正常情況下是與原來鍊錶順序相逆的,而尾插不會改變...
jdk1 7中HashMap死迴圈分析
在多執行緒環境下,使用hashmap進行put操作會引起死迴圈,導致cpu利用率接近100 hashmap在併發執行put操作時會引起死迴圈,是因為多執行緒會導致hashmap的entry鍊錶 形成環形資料結構,一旦形成環形資料結構,entry的next節點永遠不為空,就會產生死迴圈獲取entry。...
HashMap死迴圈問題追蹤
hashmap在設計之初並沒有考慮多執行緒併發的情況,多執行緒併發的情況下理論上應該使用concurrenthashmap,但是程式中經常會無意中在多併發的情況下使用了hashmap,如果是jdk1.8以下的版本,有可能會導致死迴圈,打滿cpu占用,下面基於jdk1.7原始碼分析下原因。我們從put...