集合 HashMap的不安全

2021-10-08 15:36:25 字數 2184 閱讀 3353

1.hashmap存在的問題

public static void main(string args) throws interruptedexception 

system.out.println("t1 over");}};

thread t2 = new thread()

system.out.println("t2 over");}};

t1.start();t2.start();

t1.join();t2.join();

system.out.println(map.size());

}

執行這個**,就會產生問題:

1.乙個是會產生資料丟失,普通的集合在多執行緒下面,都會產生資料丟失的問題,這個是由於執行緒私有記憶體造成的,資料沒有同步,

2.其次還會產生死迴圈問題,這個是jdk7的問題,這個存在於resize()操作,當新的空間分配之後,我們需要把資料從舊的table中,遷移到新的table,這個時候需要呼叫transfer()方法

void transfer(entry newtable)

while (e != null); //遍歷鍊錶}}

}

待resize()的結構

如果併發情況下進行rehash,如果乙個執行緒在do-while中掛起了,那麼可能就會出現下面的情況:

執行緒一,掛住(剛執行完next=e.next,那麼這個時候next=7),

執行緒二,rehash()完成

執行緒執行緒二不管了,執行緒一回來工作,繼續執行上面的do-while**內容,

newtable[i]=e        那麼table[3]就指向了key3

e=next                    那麼e=key7

這個時候e不等於null,再一次迴圈。

儲存e.next   因為執行緒2已經rehash完成,所以key7又指向key3,所以next儲存了key3

newtable[i]=e     table[3]指向key7,

e=next                e又指向key3

再一次迴圈:table[3]指向key3,e.next終於為空,但是key7還是指向key3,所以就形成了迴圈!

產生了迴圈鍊錶,那麼在get()某個元素,可能就會出現死迴圈

總結:1.在jdk1.7中,在多執行緒環境下,擴容時會造成環形鏈或資料丟失。

2.在jdk1.8中,在多執行緒環境下,會發生資料覆蓋的情況

解決辦法

1.實驗hashtable,它的方法新增了synchronized關鍵字,執行緒安全。但是鎖太重

2.將hashmap包裝,給它的方法新增synchronized,同樣鎖太重了。

3.使用concurrenthashmap

jdk8如何解決迴圈鏈問題

此處老值和新值說明:老值的意思是之前的hash值,後擴容後的hash值相同,則稱為老值,擴容後重新計算出來的hash值不同,則稱為新值

else 

else

} while ((e = next) != null);

if (lotail != null)

if (hitail != null)

}

它使用了兩個指標來分別指向頭節點和尾節點,而且還保證了元素原本的順序。它是等鍊錶迴圈結束後,才給陣列賦值,jdk7是乙個乙個插入,而jdk8是整個桶擦插入

有圖)      (jdk8的公升級)         

hashMap的執行緒不安全

hashmap是非執行緒安全的,表現在兩種情況下 1 擴容 t1執行緒對map進行擴容,此時t2執行緒來讀取資料,原本要讀取位置為2的元素,擴容後此元素位置未必是2,則出現讀取錯誤資料。2 hash碰撞 兩個執行緒新增元素發生hash碰撞,都要將此元素新增到鍊錶的頭部,則會發生資料被覆蓋。詳情 ha...

hashmap為什麼不安全

第一點多執行緒同時put的時候 在某一時刻同時操作hashmap並執行put操作,而有大於兩個key的hash值相同,如圖中a1 a2,這個時候需要解決碰撞衝突,而解決衝突的辦法上面已經說過,對於鍊錶的結構在這裡不再贅述,暫且不討論是從鍊錶頭部插入還是從尾部初入,這個時候兩個執行緒如果恰好都取到了對...

HashMap 執行緒不安全的原因

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