1.HashMap問題

HashMap問題

  1. HashMap的默認初始容量是16.如果你使用構造方法時,傳入的不是2的冪,會轉化成大於這個數的2的冪
  2. HashMap的默認初始負載因子是0.75.
  3. hashmap擴容分爲兩步:
    擴容:創建一個新的Entry空數組,長度是原數組的2倍。
    ReHash:遍歷原Entry數組,把所有的Entry重新Hash到新數組。
  4. HahMap1.7爲頭插法,1.8改進爲尾插法。

    1)Hashmap在插入元素過多的時候需要進行Resize,Resize的條件是 HashMap.Size >= Capacity * LoadFactor。2)Hashmap的Resize包含擴容和ReHash兩個步驟,ReHash在併發的情況下可能會形成鏈表環。3)當調用get方法,進入此鏈表時,會進入死循環。
    鏈表頭插法的會顛倒原來一個散列桶裏面鏈表的順序。在併發的時候原來的順序被另外一個線程a顛倒了,而被掛起線程b恢復後拿擴容前的節點和順序繼續完成第一次循環後,又遵循a線程擴容後的鏈表順序重新排列鏈表中的順序,最終形成了環。
    

  1. 當鏈表長度大 於TREEIFY THRESHOLD (默認爲8)時,將鏈表轉換爲紅黑樹,當然小於
    UNTREEIFY THRESHOLD (默認爲6)時,又會轉回鏈表以達到性能均衡。
  2. HashMap爲什麼是線程不安全的?

    HashMap在併發時可能出現的問題主要是兩方面:

  • put的時候導致的多線程數據不一致

比如有兩個線程A和B,首先A希望插入一個key value對到HashMap中,首先計算記錄所要落到的hash桶的索引座標,然後獲取到該桶裏面的鏈表頭結點,此時線程A的時間片用完了,而此時線程B被調度得以執行,和線程A-樣執行,只不過線程B成功將記錄插到了桶裏面,假設線程A插入的記錄計算出來的hash桶索弓和線程B要插入的記錄計算出來的hash桶索引是一樣的,那麼當線程B成功插入之後,線程A再次被調度運行時,它依然持有過期的鏈表頭但是它對此一無所知,以至於它認爲它應該這樣做,如此一來就覆蓋了線程B插入的記錄,這樣線程B插入的記錄就憑空消失了,造成了數據不一致的行爲。

  • resize而引|起死循環

這種情況發生在HashMap自動擴容時,當2個線程同時檢測到元素個數超過數組大小x負載因子。此時2個線程會在put()方法中調用了resize(),兩個線程同時修改一個鏈表結構會產 生一個循環鏈表JDK1.7中, 會出現resize前後元素順序倒置的情況)。接下來再想通過get(獲取某一個元素,就會出現死循環。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章