ConcurrentHashMap 簡析

為什么需要 ConcurrentHashMap

Java 早期的同步類 HashTable 和 Collections 提供的同步包裝器為我們提供了線程安全的容器踱蠢,但是因為這兩種方式都是在整個大操作 put障本、get、size 級別上加鎖實現(xiàn)的癣猾。并發(fā)效率很低。作為改進余爆,Java 提供了更為高效的并發(fā)容器——ConcurrentHashMap纷宇。

jdk 1.7 ConcurrentHashMap 分析

ConcurrentHashMap 的設計其實一直在演化,早期的 ConcurrentHashMap蛾方,其實現(xiàn)是基于:

  • 分離鎖像捶,也就是將內(nèi)部進行分段(Segment)上陕,里面則是 HashEntry 的數(shù)組,和 HashMap 類似拓春,哈希相同的條目也是以鏈表的形式存放释簿。
  • HashEntry 內(nèi)部使用 volatile 的 value 字段來保證可見性,也利用了不可變對象的機制以改進利用 Unsafe 提供的底層能力硼莽,比如 volatile access庶溶,去直接完成部分操作,以最優(yōu)化性能懂鸵,畢竟 Unsafe 中的很多操作都是 JVM intrinsic 優(yōu)化過的偏螺。

這個版本的核心是利用分段設計,在進行并發(fā)操作時匆光,鎖住相應的 Segment套像,來避免鎖住整個表,大大提高了性能终息。

構(gòu)造時夺巩,Segment 的數(shù)量由所謂的concurrentcyLevel 決定,默認是 16周崭,可以通過構(gòu)造函數(shù)顯式指定柳譬,這個輸入的值會被 Java 自動調(diào)整為最近的 2 的冪數(shù)值,比如輸入 15续镇,就會被自動調(diào)整為 16征绎。之所以這樣調(diào)整,是因為 2 的冪次方減一就是一個二進制低位全是 1 的“掩碼”磨取,在確定元素在哪個 Segment 時會利用到人柿。

在進行并發(fā)寫操作時:

  • ConcurrentHashMap 會獲取再入鎖,以保證數(shù)據(jù)一致性忙厌,Segment 本身就是基于 ReentrantLock 的擴展實現(xiàn)的凫岖,所以,在并發(fā)修改期間逢净,相應的 Segment 是被鎖定的哥放。
  • 在最初階段,進行重復性的掃描爹土,以確定相應的 key 的值是否已經(jīng)在數(shù)組里面甥雕,進而決定是更新還是放置操作。重復掃描胀茵、檢測沖突是 ConcurrentHashMap 的常見技巧社露。

另一個需要關(guān)注的點是 size 方法,它的實現(xiàn)涉及分離鎖的一個副作用琼娘。

如果不加鎖直接計算所有 Segment 的總值峭弟,在并發(fā) put 的情況下附鸽,就可能導致結(jié)果不準確,但是直接鎖定所有 Segment 進行計算瞒瘸,代價就很昂貴坷备。其實,分離鎖也限制了 Map 的初始化等操作情臭。

這個版本的 ConcurrentHashMap 是通過重試機制(RETRIES_BEFORE_LOCK省撑,指定重試次數(shù) 2),來試圖獲得可靠值俯在。如果沒有監(jiān)控到發(fā)生變化(通過對比 Segment.modCount)竟秫,就直接返回,否則獲取鎖進行操作朝巫。

jdk 1.8 ConcurrentHashMap 分析

  • 總體結(jié)構(gòu)上鸿摇,它的內(nèi)部存儲結(jié)構(gòu)變得和 HashMap 相似石景,同樣是大的桶(bucket)數(shù)組劈猿,然后內(nèi)部也是一個個所謂的鏈表結(jié)構(gòu)(bin),同步的力度要更細致一些潮孽。在單個桶中數(shù)據(jù)過多時揪荣,會進行樹化。
  • 其內(nèi)部保留了 Segment 定義往史,目的是為了保證序列化時的兼容性仗颈,不再有任何結(jié)構(gòu)上的用處。
  • 因為不再使用 Segment椎例,初始化操作大大簡化挨决,修改為 lazy-load 形式,有效避免了初始開銷订歪,解決了老版本很多人抱怨的這一點脖祈。
  • 數(shù)據(jù)存儲利用 volatile 來保證可見性。
  • 使用 CAS 等操作刷晋,在特定場景進行無鎖并發(fā)操作盖高。
  • 使用 Unsafe、LongAdder 之類的底層手段眼虱,進行極端情況的優(yōu)化喻奥。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市捏悬,隨后出現(xiàn)的幾起案子撞蚕,更是在濱河造成了極大的恐慌,老刑警劉巖过牙,帶你破解...
    沈念sama閱讀 222,000評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件诈豌,死亡現(xiàn)場離奇詭異仆救,居然都是意外死亡,警方通過查閱死者的電腦和手機矫渔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評論 3 399
  • 文/潘曉璐 我一進店門彤蔽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人庙洼,你說我怎么就攤上這事顿痪。” “怎么了油够?”我有些...
    開封第一講書人閱讀 168,561評論 0 360
  • 文/不壞的土叔 我叫張陵蚁袭,是天一觀的道長。 經(jīng)常有香客問我石咬,道長揩悄,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,782評論 1 298
  • 正文 為了忘掉前任鬼悠,我火速辦了婚禮删性,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘焕窝。我一直安慰自己蹬挺,他們只是感情好,可當我...
    茶點故事閱讀 68,798評論 6 397
  • 文/花漫 我一把揭開白布它掂。 她就那樣靜靜地躺著巴帮,像睡著了一般。 火紅的嫁衣襯著肌膚如雪虐秋。 梳的紋絲不亂的頭發(fā)上榕茧,一...
    開封第一講書人閱讀 52,394評論 1 310
  • 那天,我揣著相機與錄音客给,去河邊找鬼用押。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播灵巧,決...
    沈念sama閱讀 40,952評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼官觅!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起阐污,我...
    開封第一講書人閱讀 39,852評論 0 276
  • 序言:老撾萬榮一對情侶失蹤休涤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體功氨,經(jīng)...
    沈念sama閱讀 46,409評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡序苏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,483評論 3 341
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了捷凄。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片忱详。...
    茶點故事閱讀 40,615評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖跺涤,靈堂內(nèi)的尸體忽然破棺而出匈睁,到底是詐尸還是另有隱情,我是刑警寧澤桶错,帶...
    沈念sama閱讀 36,303評論 5 350
  • 正文 年R本政府宣布航唆,位于F島的核電站,受9級特大地震影響院刁,放射性物質(zhì)發(fā)生泄漏糯钙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,979評論 3 334
  • 文/蒙蒙 一退腥、第九天 我趴在偏房一處隱蔽的房頂上張望任岸。 院中可真熱鬧,春花似錦阅虫、人聲如沸演闭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至窝革,卻和暖如春购城,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背虐译。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評論 1 272
  • 我被黑心中介騙來泰國打工瘪板, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人漆诽。 一個月前我還...
    沈念sama閱讀 49,041評論 3 377
  • 正文 我出身青樓侮攀,卻偏偏與公主長得像,于是被迫代替她去往敵國和親厢拭。 傳聞我的和親對象是個殘疾皇子兰英,可洞房花燭夜當晚...
    茶點故事閱讀 45,630評論 2 359

推薦閱讀更多精彩內(nèi)容