Java Map、HashMap, ConcurrentHashMap全面總結(jié)

Map

HashMap

  • 環(huán)形鏈表的問題:具體見疫苗:Java HashMap的死循環(huán) | | 酷 殼 - CoolShell
    • 環(huán)形鏈表的形成是發(fā)生在并發(fā)rehash的過程中的
    • 并不是說rehash就直接導(dǎo)致死循環(huán)了,rehash只是導(dǎo)致的了環(huán)形鏈表的形成
  • 底層數(shù)據(jù)結(jié)構(gòu)
    • 數(shù)組
    • 鏈表
    • 紅黑樹
  • 擴(kuò)容
    • 時(shí)機(jī):map中的key個(gè)數(shù)達(dá)到容量c * 負(fù)載因子loadFactor的時(shí)候
    • 過程
      • 容量擴(kuò)大一倍
      • rehash一次
  • 沖突解決
    • 默認(rèn)的策略是在相應(yīng)的index位置形成鏈表
    • 當(dāng)鏈表的數(shù)量達(dá)到8個(gè)時(shí),出于性能考慮會(huì)把鏈表轉(zhuǎn)成紅黑樹
  • 快速失敗是什么意思? 集合遍歷的時(shí)候檢測是否集合中的元素個(gè)數(shù)有變動(dòng),有變動(dòng)就立即拋出異常ConcurrentModificationException

The number of times this HashMap has been structurally modified Structural modifications are those that change the number of mappings in the HashMap or otherwise modify its internal structure (e.g.,
rehash). This field is used to make iterators on Collection-views of
the HashMap fail-fast. (See ConcurrentModificationException).

  • [x]loadFactor是用來干什么的?決定是否擴(kuò)容

ConcurrentHashMap

  • 底層數(shù)據(jù)結(jié)構(gòu)
    • 數(shù)組
    • 鏈表
    • 紅黑樹
  • 擴(kuò)容過程
    • JDK7鎖住所有段,然后擴(kuò)容,保證一致性
    • JDK8多線程擴(kuò)容,標(biāo)記要遷移的點(diǎn)(要遷移的點(diǎn)node的hash值會(huì)被標(biāo)記成為MOVED,即-3),當(dāng)一個(gè)線程要獲取fh被標(biāo)記為MOVED的節(jié)點(diǎn)時(shí),要先幫忙擴(kuò)容,然后再獲取值
  • size是怎么計(jì)算的?
    • 默認(rèn)是使用baseCount,如果因?yàn)椴l(fā)導(dǎo)致這個(gè)屬性更新失敗,會(huì)使用counterCells來計(jì)數(shù)。
    • 計(jì)數(shù)的時(shí)候,會(huì)使用先計(jì)算兩次,如果沒變化,就認(rèn)為總數(shù)是正確
    • 如果一直在變化,就多嘗試兩次。如果還是失敗,就鎖全表進(jìn)行計(jì)算。
  • JDK7和JDK8上的分段鎖機(jī)制的差別
    • DK7使用ReentrantLock來實(shí)現(xiàn)分段鎖
    • JDK8使用CAS+synchronized,為什么使用synchronized+CAS, 而不是segment+ReentrantLock呢?ConcurrentHashMap 1.8為什么要使用CAS+Synchronized取代Segment+ReentrantLock - 羊飛 - 博客園
      • [x]synchronized默認(rèn)情況是偏向鎖,或者是自旋鎖,效率高,ReentrantLock則是tryLock之后就掛起,這樣導(dǎo)致有線程上下文切換的成本, JDK7版本這里會(huì)tryLock很多次
      • [x]鎖的粒度細(xì)化到了node級(jí)別,粒度更小,并發(fā)能力更大

常見面試題

Map

  • rehash的時(shí)候,鏈表上的點(diǎn)還會(huì)在同一個(gè)鏈表上么?@可能不在同一個(gè)位置上了, 這是因?yàn)橥拔恢玫挠?jì)算方式是hash&(cap-1), hash值是不變的, cap變化的情況,可能導(dǎo)致計(jì)算的index不一樣, 譬如cap為16,hash分別為5, 21, 37, rehash之后,桶的index分別為5, 21,

HashMap

  • 擴(kuò)容過程 @見上面的筆記
  • size為什么是2的整數(shù)倍?
    • 計(jì)算index的時(shí)候可以減小沖突
    • 計(jì)算index的公式 hash & (size - 1)
  • 沖突解決的過程 @見上面的筆記

ConcurrentHashMap

  • 為什么JDK8中要用CAS+synchronized替代segment+ReentrantLock的實(shí)現(xiàn)來防止并發(fā)?@見上面的筆記
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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