原文鏈接:http://blog.csdn.net/fhzaitian/article/details/51505516
------------------------------------------------------------------------
1、首先我們需要簡單地了解一下HashMap數據結構?
HashMap通常會用一個指針數組(假設為table[])來做分散所有的key,當一個key被加入時,會通過Hash算?
法通過key算出這個數組的下標i,然后就把這個<key, value>插到table[i]中,如果有兩個不同的key被算了。?
但有時候兩個key算出的下標會是一個i,那么就叫沖突,又叫碰撞,這樣會在table[i]上形成一個鏈表。所以?
如果鏈表過多或過長,查找算法則會變成低性能的鏈表遍歷,這是Hash表的缺陷。
我們都知道HashMap初始容量大小為16,一般來說,Hash表這個容器當有數據要插入時,都會檢查容量有沒有超過設定的thredhold,如果超過,需要增大Hash表的尺寸,但是這樣一來,整個Hash表里的元素都需要被重算一遍。這叫rehash,這個成本相當的大。具體大家可以看看JDK源碼
2、現在來討論死鎖產生的原因?
HashMap是非線程安全,死鎖一般都是產生于并發情況下。我們假設有二個進程T1、T2,HashMap容量為2,T1線程放入key A、B、C、D、E。在T1線程中A、B、C Hash值相同,于是形成一個鏈接,假設為A->C->B,而D、E Hash值不同,于是容量不足,需要新建一個更大尺寸的hash表,然后把數據從老的Hash表中?
遷移到新的Hash表中(refresh)。這時T2進程闖進來了,T1暫時掛起,T2進程也準備放入新的key,這時也?
發現容量不足,也refresh一把。refresh之后原來的鏈表結構假設為C->A,之后T1進程繼續執行,鏈接結構?
為A->C,這時就形成A.next=B,B.next=A的環形鏈表。一旦取值進入這個環形鏈表就會陷入死循環。
3、替代方案?
使用ConcurrentHashMap進行替代,ConcurrentHashMap是一個線程安全的Hash Table。可能有人會使用HashTable。當然HashTable也是線程安全,但HashTable鎖定的是整個Hash表,效率相對比較低。而ConcurrentHashMap可以做到讀取數據不加鎖,并且其內部的結構可以讓其在進行寫操作的時候能夠將鎖的粒度保持地盡量地小,