為什么說 HashMap 是非線程安全的?
作者丨倪升武
來源丨武哥聊編程
我們在學習 HashMap 的時候,都知道 HashMap 是非線程安全的,同時我們知道 HashTable 是線程安全的,因為里面的方法使用了 synchronized 進行同步。
但是 HashMap 為什么是非線程安全的呢?難道僅僅就是因為內(nèi)部的方法沒有 synchronized 關(guān)鍵字修飾嗎?這篇文章主要來分析一下原因。
我們知道 HashMap 底層是一個 Entry 數(shù)組,當發(fā)生 hash 沖突的時候,HashMap 是采用鏈表的方式來解決的,在對應(yīng)的數(shù)組位置存放鏈表的頭結(jié)點。對鏈表而言,新加入的節(jié)點會從頭結(jié)點加入。
1. HashMap 在插入的時候
現(xiàn)在假如 A 線程和 B 線程同時進行插入操作,然后計算出了相同的哈希值對應(yīng)了相同的數(shù)組位置,因為此時該位置還沒數(shù)據(jù),然后對同一個數(shù)組位置,兩個線程會同時得到現(xiàn)在的頭結(jié)點,然后 A 寫入新的頭結(jié)點之后,B 也寫入新的頭結(jié)點,那B的寫入操作就會覆蓋 A 的寫入操作造成 A 的寫入操作丟失。
2. HashMap 在擴容的時候
HashMap 有個擴容的操作,這個操作會新生成一個新的容量的數(shù)組,然后對原數(shù)組的所有鍵值對重新進行計算和寫入新的數(shù)組,之后指向新生成的數(shù)組。
那么問題來了,當多個線程同時進來,檢測到總數(shù)量超過門限值的時候就會同時調(diào)用 resize 操作,各自生成新的數(shù)組并 rehash 后賦給該 map 底層的數(shù)組,結(jié)果最終只有最后一個線程生成的新數(shù)組被賦給該 map 底層,其他線程的均會丟失。
3. HashMap 在刪除數(shù)據(jù)的時候
刪除這一塊可能會出現(xiàn)兩種線程安全問題,第一種是一個線程判斷得到了指定的數(shù)組位置i并進入了循環(huán),此時,另一個線程也在同樣的位置已經(jīng)刪掉了i位置的那個數(shù)據(jù)了,然后第一個線程那邊就沒了。但是刪除的話,沒了倒問題不大。
再看另一種情況,當多個線程同時操作同一個數(shù)組位置的時候,也都會先取得現(xiàn)在狀態(tài)下該位置存儲的頭結(jié)點,然后各自去進行計算操作,之后再把結(jié)果寫會到該數(shù)組位置去,其實寫回的時候可能其他的線程已經(jīng)就把這個位置給修改過了,就會覆蓋其他線程的修改。
其他地方還有很多可能會出現(xiàn)線程安全問題,我就不一一列舉了,總之 HashMap 是非線程安全的,有并發(fā)問題時,建議使用 ConcrrentHashMap。
-End-
最近有一些小伙伴,讓我?guī)兔φ乙恍?nbsp;面試題 資料,于是我翻遍了收藏的 5T 資料后,匯總整理出來,可以說是程序員面試必備!所有資料都整理到網(wǎng)盤了,歡迎下載!

面試題】即可獲取