hashMap 在多執行緒中會出現什麼問題

2021-10-05 23:54:37 字數 1691 閱讀 2664

1.當多執行緒同時put值的時候,若發生hash碰撞,可能多個元素都落在鍊錶的頭部,從而造成元素覆蓋(hashcode相同而eques值不同的元素)

列如:執行緒a put乙個元素a ,執行緒b put乙個元素b,a,b 發生hansh碰撞,本應該在map是鍊錶的形式存在,但是可能執行緒a和執行緒b同時put到鍊錶的第乙個位置,從而後來者覆蓋前者元素造成元素丟失。

該情況是出現在多線執行緒操作map擴容時會發生

jdk1.7的resize原始碼一**竟

// 擴容方法

void

resize

(int newcapacity)

entry[

] newtable =

newentry

[newcapacity]

;transfer

(newtable,

inithashseedasneeded

(newcapacity));

table = newtable;

threshold =

(int

)math.

min(newcapacity * loadfactor, maximum_capacity +1)

;}/** * transfers all entries from current table to newtable.

* 這段**主要是遍歷原集合中的所有entry, 然後依次將他們放入到新的集合中.

*/void

transfer

(entry[

] newtable,

boolean rehash)

// 獲取新下標

int i =

indexfor

(e.hash, newcapacity)

;// 第一次while迴圈時, newtable[i]是null

// 第二次while迴圈時, newtable[i]是第一次迴圈時的元素

// 原先鍊錶的順序為: 1,3,5,7,9

// 正常情況下, 擴容完成之後, 鍊錶中元素的順序為: 9,7,5,3,1

e.next = newtable[i]

;// 覆蓋上次迴圈的值, 因為上次迴圈時的值已經被鏈結到e.next上了

newtable[i]

= e;

// 繼續迴圈鍊錶上的下乙個元素

e = next;}}

}

形成迴圈鍊錶的**就在transfer方法的while迴圈中, 正是因為擴容之後鍊錶中元素的會發生逆轉, 所以會產生迴圈鍊錶.

舉例說明

/**

現有兩個執行緒: 執行緒a和執行緒b, 執行緒a進入while迴圈時, 執行到entrynext = e.next;時被掛起了, 這時該執行緒a中的e=1, e.next=11. 此時執行緒b進入while迴圈, 這時執行緒b中的e=1, e.next=11, 然後執行緒b繼續向下執行, 執行完第一次while迴圈之後, 鍊錶的順序就變為11,1,12,13,14,15. 這時元素11的下乙個元素時1,

而此時執行緒a中元素1的下乙個元素為11. 完美! 產生了迴圈鍊錶!

通俗來講:執行緒a和執行緒b 操作了通乙個鍊錶e ,造成了這種結果。

jdk1.8中改進了resize方法,改進之後的方法不再進行鍊錶的逆轉, 而是保持原有鍊錶的順序, 如果在多執行緒環境下, 頂多會在鍊錶後邊多追加幾個元素而已, 不會出現環的情況.

面試中會出現的專案問題

一 專案介紹 1.請介紹一下你簡歷上最熟的專案。回答要點 1 所要介紹的專案一定要是你最近完成的專案,在簡歷上的位置是第 乙個 2 要明確的說出專案名稱,且專案名稱要與簡歷上所寫的要一致 3 要明確的表述出專案的開發背景和功能模組組成。4 重點介紹自己所負責的那塊內容,如果有業務流程請介紹出業務流程...

springMVC傳參中會出現中文亂碼

springmvc傳參中會出現中文亂碼問題。學習中提供了兩種解決方案 第一種是在tomcat中加引數 第二種是在配置中加filter引數 通過自己的測試發現光有第一種方法不一定有效果,但是用了第二種方法肯定是ok的。tomcat中引數如下 server.xml web.xml的filter配置如下 ...

HashMap在多執行緒下的死鎖和覆蓋原因

hashmap在jdk7之前,會產生死鏈和資料丟失這個問題 hashmap進行儲存時,如果size超過當前最大容量 負載因子時候會發生resize,首先看一下resize原 void resize int newcapacity entry newtable new entry newcapacit...