★
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...