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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

ConcurrentHashMap底层原理?

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

本文為面試必備系列篇,不深入敘述,具體細(xì)節(jié)可自行查詢。

可能會問的問題

1、用過ConcurrentHashMap嗎?
2、為什么要用ConcurrentHashMap
3、HashMapHashTable的區(qū)別,引出ConcurrentHashMap
4、HashMap在多線程環(huán)境下存在線程安全問題,那你一般都是怎么處理這種情況的?
5、能說一下ConcurrentHashMap是怎么實(shí)現(xiàn)的嗎?

為什么要用ConcurrentHashMap?

在并發(fā)編程中使用HashMap可能會導(dǎo)致程序陷入死循環(huán),而使用線程安全的HashTable效率又非常低,所以采用了ConcurrentHashMap

單看這個(gè)回答,就會牽扯到「為和編發(fā)編程中使用HashMap會導(dǎo)致程序陷入死循環(huán)?」和「HashTable為何效率低下?」這兩個(gè)問題,具體可參考上篇 > 面試必備:HashMap底層數(shù)據(jù)結(jié)構(gòu)?jdk1.8算法優(yōu)化,hash沖突,擴(kuò)容等問題

關(guān)于ConcurrentHashMap實(shí)現(xiàn)原理的兩個(gè)參考回答,自己可以重新組織一下:

ConcurrentHashMap采用的是分段式鎖,與之對應(yīng)的就是HashTableHashTable使用的是Synchronize關(guān)鍵字,是對一個(gè)大的數(shù)組加一把鎖,其實(shí)是對對象加鎖,鎖住的是對象整體,性能肯定是比較差的,現(xiàn)在ConcurrentHashMap是將大數(shù)組拆分成許多的小數(shù)組,每一個(gè)小數(shù)組擁有一把鎖,允許多個(gè)修改操作并發(fā)進(jìn)行。

ConcurrentHashMap采用的是分段式鎖,可以理解為把一個(gè)大的Map拆封成N個(gè)小的Segment,在put數(shù)據(jù)時(shí)會根據(jù)hash來確定具體存放在哪個(gè)Segment中,Segment內(nèi)部的同步機(jī)制是基于Lock操作的,每一個(gè)Segment都會分配一把鎖,當(dāng)線程占用鎖訪問其中一段數(shù)據(jù)時(shí),其他段的數(shù)據(jù)也能被其他線程訪問,也就是實(shí)現(xiàn)并發(fā)訪問。

繼續(xù)拓展,分段式鎖是如何實(shí)現(xiàn)的?

ConcurrentHashMapJDK1.7JDK1.8之間是有區(qū)別的,當(dāng)然,這個(gè)問題也可以這樣問:

能說一下ConcurrentHashMap在JDK1.7和JDK1.8中的區(qū)別嗎?

1、JDK1.7:

HashEntry數(shù)組 + Segment數(shù)組 + Unsafe 「大量方法運(yùn)用」

JDK1.7中數(shù)據(jù)結(jié)構(gòu)是由一個(gè)Segment數(shù)組和多個(gè)HashEntry數(shù)組組成的,每一個(gè)Segment元素中存儲的是HashEntry數(shù)組+鏈表,而且每個(gè)Segment均繼承自可重入鎖ReentrantLock,也就帶有了鎖的功能,當(dāng)線程執(zhí)行put的時(shí)候,只鎖住對應(yīng)的那個(gè)Segment 對象,對其他的 Segmentget put 互不干擾,這樣子就提升了效率,做到了線程安全。

額外補(bǔ)充:我們對 ConcurrentHashMap 最關(guān)心的地方莫過于如何解決 HashMapput 時(shí)候擴(kuò)容引起的不安全問題?

JDK1.7ConcurrentHashMapput 方法中進(jìn)行了兩次 hash 計(jì)算去定位數(shù)據(jù)的存儲位置,盡可能的減小哈希沖突的可能行,然后再根據(jù) hash 值以 Unsafe 調(diào)用方式,直接獲取相應(yīng)的 Segment,最終將數(shù)據(jù)添加到容器中是由 segment對象的 put 方法來完成。由于 Segment 對象本身就是一把鎖,所以在新增數(shù)據(jù)的時(shí)候,相應(yīng)的 Segment對象塊是被鎖住的,其他線程并不能操作這個(gè) Segment 對象,這樣就保證了數(shù)據(jù)的安全性,在擴(kuò)容時(shí)也是這樣的,在 JDK1.7 中的 ConcurrentHashMap擴(kuò)容只是針對 Segment 對象中的 HashEntry 數(shù)組進(jìn)行擴(kuò)容,還是因?yàn)?Segment 對象是一把鎖,所以在 rehash 的過程中,其他線程無法對 segmenthash 表做操作,這就解決了 HashMapput 數(shù)據(jù)引起的閉環(huán)問題。

2、JDK1.8:

JDK1.7:ReentrantLock+Segment+HashEntry
JDK1.8:Synchronized+CAS+Node+紅黑樹

JDK1.8屏蔽了JDK1.7中的Segment概念呢,而是直接使用「Node數(shù)組+鏈表+紅黑樹」的數(shù)據(jù)結(jié)構(gòu)來實(shí)現(xiàn),并發(fā)控制采用 「Synchronized + CAS機(jī)制」來確保安全性,為了兼容舊版本保留了Segment的定義,雖然沒有任何結(jié)構(gòu)上的作用。

總之JDK1.8中優(yōu)化了兩個(gè)部分:

放棄了 HashEntry 結(jié)構(gòu)而是采用了跟 HashMap 結(jié)構(gòu)非常相似的 Node數(shù)組 + 鏈表(鏈表長度大于8時(shí)轉(zhuǎn)成紅黑樹)的形式

Synchronize替代了ReentrantLock,我們一直固有的思想可能覺得,Synchronize是重量級鎖,效率比較低,但為什么要替換掉ReentrantLock呢?

1、隨著JDK版本的迭代,本著對Synchronize不放棄的態(tài)度,內(nèi)置的Synchronize變的越來越“輕”了,某些場合比使用API更加靈活。

2、加鎖力度的不同,在JDK1.7中加鎖的力度是基于Segment的,包含多個(gè)HashEntry,而JDK1.8鎖的粒度就是HashEntry(首節(jié)點(diǎn)),也就是1.8中加鎖力度更低了,在粗粒度加鎖中 ReentrantLock 可能通過 Condition 來控制各個(gè)低粒度的邊界,更加的靈活,而在低粒度中,Condition的優(yōu)勢就沒有了,所以使用內(nèi)置的 Synchronize 并不比ReentrantLock效果差。

18年專科畢業(yè)后,期間一度迷茫,最近我創(chuàng)建了一個(gè)公眾號用來記錄自己的成長。

總結(jié)

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

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