日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

聊聊ConcurrentHashMap

發(fā)布時(shí)間:2024/8/1 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 聊聊ConcurrentHashMap 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

聊聊ConcurrentHashMap

一、為什么需要ConcurrentHashMap

1、HashMap 線(xiàn)程不安全

在多線(xiàn)程環(huán)境下,使用HashMap進(jìn)行 put 操作的時(shí)候可能造成死循環(huán),導(dǎo)致 CPU 使用率太高

為什么HashMap線(xiàn)程不安全?

在 put 的時(shí)候,插入元素超過(guò)了容量,就會(huì)進(jìn)行rehash,這個(gè)會(huì)重新將原數(shù)組的內(nèi)容重新hash到新的擴(kuò)容數(shù)組中,在多線(xiàn)程的環(huán)境下,存在同時(shí)其他的元素也在進(jìn)行 put 操作,如果 hash 值相同,可能出現(xiàn)同時(shí)在同一數(shù)組下用鏈表表示,造成閉環(huán),導(dǎo)致在 get 時(shí)會(huì)出現(xiàn)死循環(huán),所以不安全

2、HashTable 安全但是效率太低了

因?yàn)?HashTable 是利用 synchronized 來(lái)保證線(xiàn)程安全的,在線(xiàn)程競(jìng)爭(zhēng)激烈的情況下效率將會(huì)非常低。因?yàn)樵谝粋€(gè)線(xiàn)程訪(fǎng)問(wèn)同步方法的時(shí)候,其他線(xiàn)程只能阻塞等待。

二、ConcurrentHashMap 的 好處

實(shí)現(xiàn)了前面的兩個(gè)問(wèn)題 :線(xiàn)程安全了 并且也解決了HashTable 效率低下的問(wèn)題

三、怎么解決效率低下的問(wèn)題

這個(gè)主要是運(yùn)用了分段鎖(segment)的思想

HashTable 為什么效率低,就是因?yàn)樗嵌鄠€(gè)線(xiàn)程競(jìng)爭(zhēng)同一把鎖,那么如果容器里面有很多把鎖,這個(gè)問(wèn)題是不是就可以解決了,這個(gè)就是ConcurrentHashMap所使用的分段鎖技術(shù)。

首先將數(shù)據(jù)分為一段一段的進(jìn)程存儲(chǔ),然后給每一段分別加上鎖,當(dāng)一個(gè)線(xiàn)程占用鎖訪(fǎng)問(wèn)其中一個(gè)段的數(shù)據(jù)的時(shí)候,其他段的數(shù)據(jù)也可以被其他線(xiàn)程訪(fǎng)問(wèn)。

接下來(lái)我們就重點(diǎn)講講分段鎖吧

ConcurrentHashMap 是由Segment 數(shù)組結(jié)構(gòu)和HashEntry數(shù)組結(jié)構(gòu)組成的。Segment是一種可重入鎖ReentrantLock,在 ConcurrentHashMap 里面扮演鎖的角色,HashEntry 則是用來(lái)村塾鍵值對(duì)數(shù)據(jù)。一個(gè) ConcurrentHashMap 里面包含一個(gè) Segment數(shù)組,Segment的結(jié)構(gòu)和HashMap類(lèi)似,是一種數(shù)組+鏈表結(jié)構(gòu),一個(gè)Segment里面包含一個(gè) HashEntry數(shù)組,每個(gè)HashEntry是一個(gè)鏈表節(jié)點(diǎn)構(gòu)成的元素,每個(gè)Segment守護(hù)一個(gè)HashEntry數(shù)組里面的元素,當(dāng)對(duì)HashEntry數(shù)組的元素進(jìn)行修改時(shí),必須首先獲得它對(duì)應(yīng)的Segment鎖。可以說(shuō),ConcurrentHashMap是一個(gè)二級(jí)的哈希表。在一個(gè)總的哈希表下面還有若干個(gè)子哈希表。

四、采用分段鎖技術(shù)的好處:并發(fā)的讀寫(xiě)

case1:不同Segment的并發(fā)寫(xiě)入:

不同的Segment的寫(xiě)入是可以并發(fā)執(zhí)行的

case 2:同一個(gè)Segment 的寫(xiě)

Segment的寫(xiě)入是需要上鎖的,因此對(duì)同一個(gè)Segment的并發(fā)寫(xiě)會(huì)被阻塞

case 3:同一個(gè)Segment 的寫(xiě)-讀

同一個(gè)Segment的寫(xiě)-讀是可以并發(fā)執(zhí)行的

五、詳細(xì)看看 讀-寫(xiě) 的過(guò)程

1、讀:Get()

  • 為輸入的Key做 Hash 運(yùn)算,得到 hash 值
  • 通過(guò) hash 值,定位到對(duì)應(yīng)的Segment 對(duì)象
  • 再次通過(guò) hash 值,定位到 Segment 當(dāng)中數(shù)組的具體位置

讀操作其實(shí)是沒(méi)有鎖的,第一次通過(guò) hash 定位到 Segment 上,第二次通過(guò) hash 定位到 具體元素上。因?yàn)?hashEntry 中的 value 屬性是用 volatile 修飾的,保證了可見(jiàn)性,所以每次獲取的都死最新值。

2、寫(xiě):Put()

  • 為輸入的 Key 做 Hash 運(yùn)算,得到 hash 值
  • 通過(guò) hash 值,定位到對(duì)應(yīng)的 Segment 對(duì)象
  • 獲取可重入鎖
  • 再次通過(guò) hash 值,定位到 Segment 當(dāng)中數(shù)組的具體位置
  • 插入或覆蓋 HashEntry 對(duì)象
  • 釋放鎖

總結(jié):可以看出ConcurrentHashMap在讀寫(xiě)的時(shí)候都需要兩次定位。首先是定位到 Segment ,然后再定位到 Segment 下的具體的數(shù)組下標(biāo)

六、size() 怎么 解決一致性問(wèn)題

size()目的是統(tǒng)計(jì)ConcurrentHashMap的總元素?cái)?shù)量,自然需要把各個(gè)Segment 內(nèi)部的元素都加起來(lái)。但是在統(tǒng)計(jì)數(shù)量的時(shí)候,有可能 已經(jīng)統(tǒng)計(jì)過(guò)的Segment順佳插入了新的元素,這個(gè)時(shí)候應(yīng)該怎么辦?下面我們來(lái)看看ConcurrentHashMap的size(),他是一個(gè)嵌套循環(huán),大致邏輯如下:

  • 遍歷所有的 Segment
  • 把 Segment 的元素?cái)?shù)量累加起來(lái)
  • 把 Segment 的修改次數(shù)累加起來(lái)
  • 判斷所有 Segment 的總修改次數(shù)是否大于上一次的總修改次數(shù)。如果大于,說(shuō)明統(tǒng)計(jì)過(guò)程中有修改,重新統(tǒng)計(jì),嘗試次數(shù)+1;如果不是,說(shuō)明沒(méi)有修改,統(tǒng)計(jì)結(jié)束
  • 如果嘗試次數(shù)超過(guò)閾值,則對(duì)每一個(gè) Segment 加鎖,在重新統(tǒng)計(jì)
  • 再次判斷所有 Segment 的總修改次數(shù)是否大于上一次的總修改次數(shù)。由于已經(jīng)加鎖,次數(shù)一定和上一次相同
  • 釋放鎖,統(tǒng)計(jì)結(jié)束
  • 總結(jié):一開(kāi)始對(duì) Segment 不加鎖,而是直接嘗試將所有的 Segment 元素中的count相加,這樣執(zhí)行兩次,然后將兩次的結(jié)果進(jìn)行對(duì)比,如果兩次結(jié)果相同則直接返回;如果不相同,則將所有的Segment加鎖,然后再次執(zhí)行統(tǒng)計(jì)得到對(duì)應(yīng)的 size 值。

    七、再看看1.8是怎么實(shí)現(xiàn)的

    1.8 拋棄了分段鎖(Segment),而是采取的是 CAS + Synchronized 的方式

    將1.7里面的 HashEntry 改為 Node ,但是作用是一樣的。

    先看看一個(gè)概念:樂(lè)觀(guān)鎖和悲觀(guān)鎖

    悲觀(guān)鎖:認(rèn)為對(duì)于同一個(gè)數(shù)據(jù)的并發(fā)操作,一定是為發(fā)生修改的

    樂(lè)觀(guān)鎖:對(duì)于同一個(gè)數(shù)據(jù)的并發(fā)操作是不會(huì)發(fā)生修改的,在更新的時(shí)候會(huì)采取嘗試更新不斷嘗試的方式更新數(shù)據(jù)

    CAS(compare and swap,比較交換)原理:

    CAS有三個(gè)操作數(shù),內(nèi)存值V、預(yù)期值A(chǔ)、要修改的值B,當(dāng)且僅當(dāng)A和V相等時(shí)才會(huì)將V修改為B,否則什么也不會(huì)做。

    CAS的缺點(diǎn):

    存在 ABA 問(wèn)題,解決辦法,添加版本號(hào)

    循環(huán)時(shí)間長(zhǎng),開(kāi)銷(xiāo)大

    只能保證一個(gè)共享變量的原子操作

    總結(jié)

    以上是生活随笔為你收集整理的聊聊ConcurrentHashMap的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。