HashMap之原理及死鎖

一、HashMap原理
1.HashMap的本質就是數組和鏈表。table是一個entry數組,每一個數組元素保存一個Entry節點,而Entry節點內部又連接着同樣key的下一個Entry節點,就構成了鏈表。.
詳情見 HashMap源碼分析

2.HashMap死鎖原因:
HashMap會造成死鎖,因爲HashMap是線程非安全的,多併發的情況容易造成死鎖,若要高併發推薦使用ConcurrentHashMap。這裏的加了鎖。
高併發時引起HashMap死鎖的原因分析:
HashMap死鎖原因分析
總的來說是:
Hash表的初始大小(HashMap初始容量大小爲16)有限,當put存入的數據增加時就必須擴容了,源碼中會調用rehash方法(即是把原表內容移入到一個新的表中),單線程下rehash就是把原來鏈表遍歷,從新的鏈表頭部(爲什麼不加到新鏈表最後?因爲複雜度是 O(N))挨個放入,放入的過程中依次執行函數transfer();

Entry<K,V> next = e.next;//保留頭指針的下一個節點——因爲是單鏈表,如果要轉移頭指針,一定要保存下一個結點,不然轉移後鏈表就丟了
e.next = newTable[i];//插入到鏈表的頭部——e 要插入到鏈表的頭部,所以要先用 e.next 指向新的 Hash 表第一個元素(爲什麼不加到新鏈表最後?因爲複雜度是 ON))

newTable[i] = e;//——現在新 Hash 表的頭指針仍然指向 e 沒轉移前的第一個元素,所以需要將新 Hash 表的頭指針指向 e

e = next//——轉移 e 的下一個

假設現在有三個線程:T1,T2,T3;在老數組中的第一個數據也就是e引用的對象,我們稱它爲A,在新數組中的頭兩個數據分別爲B和C,B.next=C。
線程T1運行到e.next=newTable[i]時線程T2運行到next=e.next;然後線程t1去繼續;
運行,會產生什麼效果呢?A.next=B,B.next=C。e指向的對象是B,newTable[i]=A。然後繼續運行,e.next=newTable[i],也就是B.next=A;同時A.next=B,繼續運行newTable[i] = e,e = next;如果沒有其它線程搗亂的話,那麼此時e應該是C啊,可惜只是如果,如果有第三個線程T3在線程T1執行e.next = newTable[i]的時候去執行next = e.next;那麼就中途改變了next的值,本來是保存C的,但是現在成了A了。總結下現在的情況:e引用A,nextTable[i]引用B,A.next=B,B.next=A。現在明白了吧。會一直這麼死鎖下去的。

發佈了37 篇原創文章 · 獲贊 20 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章