如何線程安全使用HashMap

背景

  • HashTable繼承Dictionary類,是線程安全的,但是效率低,因為HashTable使用了synchronized,所有線程經(jīng)常同一把鎖
  • ConcurrentHashMap是線程安全而且效率高,因為它包含了一個Segment數(shù)組,將數(shù)據(jù)分段存儲,給每一段詩句配一把鎖,也就是所謂的所分段技術(shù)
  • JDK7采用了位桶+鏈表的方式,即散列鏈表的方式實現(xiàn)的;JDK8采用的是位桶+鏈表/紅黑樹的方式實現(xiàn),也是非線程安全。當(dāng)某個位桶的鏈表的長度達(dá)到某個閥值時,這個鏈表就轉(zhuǎn)換為紅黑樹

HashMap為什么線程不安全

HashMap的自動擴(kuò)容機(jī)制

HashMap內(nèi)部存儲使用了一個Node數(shù)組,而Node類包含一個類型為Node的next變量,也就是相當(dāng)于一個鏈表,所有的hash值相同(即產(chǎn)生了沖突)的key值會存儲到同一個鏈表中。HashMao內(nèi)部的Node數(shù)組默認(rèn)的大小是16,默認(rèn)的負(fù)載因子是0.75,當(dāng)HashMap中的元素超過16\0.75=12時,會把數(shù)組擴(kuò)展為2*16=32,并重新計算每個元素在新數(shù)組中的位置

并發(fā)下的HashMap使用

  • 如果多個線程同時使用put方法添加元素,而且假設(shè)正好存在兩個put的key值發(fā)生了碰撞,即hash值一樣,那么根據(jù)hashmap的實現(xiàn),這兩個key會添加到數(shù)組的同一個位置,這樣會造成其中一個線程的put的數(shù)據(jù)會被覆蓋。
  • 如果多個線程同時檢測到元素個數(shù)超過數(shù)組大小*loadfactor,這樣會發(fā)生多個線程同時對Node數(shù)組進(jìn)行擴(kuò)容,都在重新計算元素位置以及復(fù)制數(shù)據(jù),但是最終只有一個線程擴(kuò)容后的數(shù)組會賦值給table,換言之,其他線程的都會丟失,并且各自線程的put數(shù)據(jù)也丟失了
HashMap在并發(fā)執(zhí)行put操作時會引起死循環(huán),導(dǎo)致CPU利用率接近100%,因>為多線程會導(dǎo)致hashmap中的Node鏈表形成環(huán)形數(shù)據(jù)結(jié)構(gòu),一旦形成環(huán)形數(shù)據(jù)結(jié)構(gòu),Node的next節(jié)點永遠(yuǎn)不為空,就會在獲取node時候產(chǎn)生死循環(huán)

如何線程安全使用

  • hashtable

Map<String, String> hashtable = new Hashtable<>();

  • Concurrenthashmap

Map<String, String> concurrentHashMap = new ConcurrentHashMap<>();

  • SyncronizedMap

Map<String, String> synchronizedHashMap = Collections.synchronizedMap(new HashMap<String, String>());

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容