注:源圖和總結來自享學課堂,自己消化之後略有補充修改
備註:基於1.7jdk進行分析
備註2:強烈建議自己跟着步驟一個圖一個圖手動畫,理解深刻一點也快一點
簡介
在多線程之下,在put操作的時候,會導致HashMap的Entry鏈表死循環,導致CPU利用率接近100%
單線程下HashMap的擴容
原理
擴容只要有三個方法:
AddEntry
resize
transfer
擴容總結
1、擴容2倍
2、新建數組,容量是以前的2倍
3、輪詢oldtable上的值,計算在newtable中的位置,採用頭插法以鏈表形式連接
實例
有如下的hashMap
按照代碼中的方法,移動如下
第一次:
第二次:
第三次:
併發下的擴容
初始值:
線程1剛執行完Entry<K,V> next = e.next;就被阻塞了,線程2已經完成了所有的擴擴容操作,剛執行完Entry<K,V> next = e.next;,只剩下e.next = newTable[3] ; newTable[3] = e; e=next
此時線程的狀態是這個樣子
接下來線程1開始執行newTable[i]=e,即newTable[3]=e
執行e=next
開始新一輪循環
最開始線程2不是還有最後一點沒有執行完嗎e.next = newTable[3] ; newTable[3] = e; e=next,這個時候線程2完全執行完成
此時執行Entry<key,value> next = e.next;
執行e.next= newTable[3];,newTable[3] =e;
執行e=next;於是e=key(3);
開始新一輪while循環
執行e.next = newTable[i],newTable[i]=e;後,循環鏈表產生
產生循環鏈表之後,一旦線程調用get查找一個不存在的元素是(例如11,15),就會進入死循環,CPU消耗100%
總結:
HashMap的死循環是在併發擴容下發生的,因爲一個線程先進行了擴容變成了倒序鏈表,後一個線程再擴容是,又進行了自己的散列,再次將倒序鏈表變成了正序鏈表,於是形成了一個環形,當get表中不存在的元素是,造成死循環