hashMap的執行緒不安全

2022-07-20 14:30:20 字數 3229 閱讀 1819

hashmap是非執行緒安全的,表現在兩種情況下:

1 擴容:

t1執行緒對map進行擴容,此時t2執行緒來讀取資料,原本要讀取位置為2的元素,擴容後此元素位置未必是2,則出現讀取錯誤資料。

2 hash碰撞

兩個執行緒新增元素發生hash碰撞,都要將此元素新增到鍊錶的頭部,則會發生資料被覆蓋。

詳情:

hashmap底層是乙個node陣列,一旦發生hash衝突的的時候,hashmap採用拉鍊法解決碰撞衝突,node結構:

/**

* basic hash bin node, used for most entries. (see below for

* treenode subclass, and in linkedhashmap for its entry subclass.)

*/static

class nodeimplements map.entry

public

final k getkey()

public

final v getvalue()

public

final string tostring()

public

final

inthashcode()

public

final

v setvalue(v newvalue)

public

final

boolean

equals(object o)

return

false

; }

}

node的變數:

final

inthash;

final

k key;

v value;

node

next;

執行put方法新增元素後呼叫此方法:
/**

* implements map.put and related methods**

@param

hash hash for key

* @param

key the key

* @param

value the value to put

* @param

onlyifabsent if true, don't change existing value

* @param

evict if false, the table is in creation mode.

* @return

previous value, or null if none

*/final v putval(int hash, k key, v value, boolean

onlyifabsent,

boolean

evict)

//如果發現相同的key,同樣覆蓋

if (e.hash == hash &&((k = e.key) == key || (key != null &&key.equals(k))))

break

; p =e;}}

if (e != null)

}++modcount;

if (++size >threshold)

resize();

afternodeinsertion(evict);

return

null

; }

在併發情況下,新增元素,在 1位置 會出現執行緒安全問題

擴容問題:

/**

* initializes or doubles table size. if null, allocates in

* accord with initial capacity target held in field threshold.

* otherwise, because we are using power-of-two expansion, the

* elements from each bin must either stay at same index, or move

* with a power of two offset in the new table.**

@return

the table

*/final node resize()

//如果當前長度*2 小於最大值,並且當前長度大於等於預設長度16,閾值*2

else

if ((newcap = oldcap << 1) < maximum_capacity &&oldcap >=default_initial_capacity)

newthr = oldthr << 1; //

double threshold

}

//如果閾值大於0,則將新陣列的長度設定為閾值=16

else

if (oldthr > 0) //

initial capacity was placed in threshold

newcap =oldthr;

//零初始閾值表示使用預設值

else

if (newthr == 0)

threshold =newthr;

@suppresswarnings()

//建立新的陣列

node newtab = (node)new

node[newcap];

table =newtab;

//將舊資料遷移到新陣列

if (oldtab != null

)

else

} while ((e = next) != null

);

if (lotail != null

)

if (hitail != null

) }}}

}return

newtab;

}

執行緒1在取資料時,map被其它執行緒擴容,則造成取到錯誤資料

HashMap 執行緒不安全的原因

hashmap執行緒安全的問題,在各大面試中都會被問到,屬於常考熱點題目。雖然大部分讀者都了解它不是執行緒安全的,但是再深入一些,問它為什麼不是執行緒安全的,仔細說說原理,用圖畫出一種非執行緒安全的情況?1.8之後又做了什麼改善了這點?很多讀者可能一時想不出很好的答案。我們關注下面的 void tr...

談談HashMap執行緒不安全的體現

hashmap的原理以及如何實現,之前在 jdk7與jdk8中hashmap的實現 中已經說明了。那麼,為什麼說hashmap是執行緒不安全的呢?它在多執行緒環境下,會發生什麼情況呢?1.resize死迴圈 我們都知道hashmap初始容量大小為16,一般來說,當有資料要插入時,都會檢查容量有沒有超...

hashmap的執行緒不安全性

首先hashmap在多個執行緒同時對其操作的時候造成的髒讀很統一理解,比如乙個執行緒a對hashmap進行讀操作,乙個執行緒b對hashmap就行寫操作。執行緒b先進入put方法中,此時還沒有寫資料的時候執行緒a輪轉執行,並一直執行到結束,假設執行取到資料為條,這時執行緒b繼續執行新增了一條資料。那...