摘要:與中的類似,也是一個(gè)數(shù)組加鏈表,不過(guò)這個(gè)線程安全。線程安全,但是它的線程安全是依賴將所有修改的代碼塊都用修飾。這是中實(shí)現(xiàn)線程安全的思路,由個(gè)組成,每個(gè)就相當(dāng)于一個(gè)數(shù)組鏈表。線程安全,但性能差,不推薦使用。
問(wèn)題描述 翻翻別人的面試經(jīng)歷
這里在知乎上看到的,分享出了自己面試阿里Java崗的面試題。
看了一下,除了Spring之外的其他很多題都不會(huì),但是不能拿學(xué)校沒(méi)講Java作為借口,因?yàn)榭赡苤v了也不會(huì)。
但是第九個(gè)問(wèn)題,我覺(jué)得應(yīng)該立刻話時(shí)間研究研究了,因?yàn)橹霸诰彺嬷杏玫搅诉@個(gè)。
當(dāng)時(shí)也不明白具體HashMap和ConcurrentHashMap究竟有什么區(qū)別。
只是記得之前看過(guò)有關(guān)大數(shù)據(jù)的場(chǎng)景下利用緩存減輕數(shù)據(jù)庫(kù)壓力的文章,文中說(shuō)常用ConcurrentHashMap,所以這里緩存就用這個(gè)了,其實(shí)并不懂原理,下面,讓我們一起來(lái)研究一下。
MapMap大家都熟悉了,Java中也有,JavaScript中也有。
Map是一種鍵值對(duì)類型的數(shù)據(jù)結(jié)構(gòu),根據(jù)鍵映射到值。
不分析源碼了,就把思想給大家講一下,以下主要以圖為主。
HashMap Java7HashMap的本質(zhì)是一個(gè)可變長(zhǎng)度的數(shù)組,在數(shù)組中每個(gè)位置保存的是一個(gè)Entry節(jié)點(diǎn),該節(jié)點(diǎn)存儲(chǔ)有hash、key、value、next等信息。
Java7中的HashMap實(shí)現(xiàn)與我們?cè)跀?shù)據(jù)結(jié)構(gòu)中學(xué)習(xí)的類似,對(duì)key進(jìn)行hash,如果沖突了,則添加到鏈表中。
然后查詢的時(shí)候就先根據(jù)hash找到相應(yīng)的位置,然后根據(jù)鏈表逐一比較,返回相應(yīng)的value。時(shí)間復(fù)雜度取決于鏈表的長(zhǎng)度,時(shí)間復(fù)雜度為O(N)。
Java8Java8中對(duì)HashMap進(jìn)行了優(yōu)化,如果鏈表中元素超過(guò)8個(gè)時(shí),就將鏈表轉(zhuǎn)化為紅黑樹(shù),以減少查詢的復(fù)雜度,將時(shí)間復(fù)雜度降低為O(logN)。
HashMap沒(méi)有對(duì)多線程的場(chǎng)景下做任何的處理,不用說(shuō)別的,就兩個(gè)線程同時(shí)put,然后沖突了,兩者需要操作一個(gè)鏈表/紅黑樹(shù),這肯定就會(huì)有錯(cuò)誤發(fā)生,所以HashMap是線程不安全的。
HashTableHashTable與Java7中的HashMap類似,也是一個(gè)數(shù)組加鏈表,不過(guò)這個(gè)線程安全。
HashTable線程安全,但是它的線程安全是依賴將所有修改HashTable的代碼塊都用synchronized修飾。
synchronized關(guān)鍵字我們之前在單例模式中用到過(guò),它修飾的代碼塊,同一時(shí)刻只允許一個(gè)線程訪問(wèn),其他線程會(huì)被阻塞,等待該線程執(zhí)行完再執(zhí)行。
所以,在HashTable中,一個(gè)線程在put,其余的線程在get的時(shí)候就會(huì)被阻塞,無(wú)法并行。所以不推薦使用HashTable,雖然它線程安全。
ConcurrentHashMapHashMap線程不安全,HashTable性能又不好,當(dāng)然需要設(shè)計(jì)一個(gè)新類去解決這些問(wèn)題,這就是ConcurrentHashMap。
Java7這是Java7中實(shí)現(xiàn)線程安全的思路,ConcurrentHashMap由16個(gè)segment組成,每個(gè)segment就相當(dāng)于一個(gè)HashMap(數(shù)組+鏈表)。
segment最多16個(gè),想要擴(kuò)容,就是擴(kuò)充每個(gè)segment中數(shù)組的長(zhǎng)度。
然后只要實(shí)現(xiàn)每個(gè)segment是線程安全的,就讓這個(gè)Map線程安全了。每個(gè)segment是加鎖的,對(duì)修改segment的操作加鎖,不影響其他segment的使用,所以理想情況下,最多支持16個(gè)線程并發(fā)修改segment,這16個(gè)線程分別訪問(wèn)不同的segment。
同時(shí),在segment加鎖時(shí),所有讀線程是不會(huì)受到阻塞的。
這樣設(shè)計(jì),put與get的基本操作就是先找segment,再找segment中的數(shù)組位置,再查鏈表。
Java8后來(lái)人們發(fā)現(xiàn)Java7這樣設(shè)計(jì)太復(fù)雜了,回歸本質(zhì)。
HashMap線程不安全的問(wèn)題完全都是出在對(duì)鏈表/紅黑樹(shù)的操作上,為什么非要建一個(gè)segment加鎖呢?直接對(duì)鏈表/紅黑樹(shù)加鎖不就好了?
所以Java8的ConcurrentHashMap完全就是HashMap進(jìn)行加鎖,實(shí)現(xiàn)線程安全。
這里總結(jié)的很簡(jiǎn)單,其實(shí)源碼中對(duì)這個(gè)的實(shí)現(xiàn)特別復(fù)雜,有興趣的可以去看看,反正我是看著頭大。
總結(jié)HashMap線程不安全。
HashTable線程安全,但性能差,不推薦使用。
ConcurrentHashMap線程安全。
ConcurrentHashMap在Java7中使用segment實(shí)現(xiàn),對(duì)每個(gè)segment加鎖。
ConcurrentHashMap在Java8中是直接在HashMap的基礎(chǔ)上進(jìn)行加鎖。
參考文獻(xiàn):
Java7/8 中的 HashMap 和 ConcurrentHashMap 全解析
ConcurrentHashMap、HashTable、HashMap三兄弟
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/76851.html
摘要:若遇到哈希沖突,則將沖突的值加到鏈表中即可。之后相比于之前的版本,之后在解決哈希沖突時(shí)有了較大的變化,當(dāng)鏈表長(zhǎng)度大于閾值默認(rèn)為時(shí),將鏈表轉(zhuǎn)化為紅黑樹(shù),以減少搜索時(shí)間。有序,唯一紅黑樹(shù)自平衡的排序二叉樹(shù)。 本文是最最最常見(jiàn)Java面試題總結(jié)系列第三周的文章。主要內(nèi)容: Arraylist 與 LinkedList 異同 ArrayList 與 Vector 區(qū)別 HashMap的底層...
摘要:中的使用及在中的沖突方案引言簡(jiǎn)稱是在作為的替代選擇新引入的,是包的重要成員。為了解決在頻繁沖突時(shí)性能降低的問(wèn)題,中使用平衡樹(shù)來(lái)替代鏈表存儲(chǔ)沖突的元素。目前,只有和會(huì)在頻繁沖突的情況下使用平衡樹(shù)。 java中ConcurrentHashMap的使用及在Java 8中的沖突方案 1、引言 ConcurrentHashMap(簡(jiǎn)稱CHM)是在Java 1.5作為Hashtable的替代選擇新...
摘要:如下代碼省略相關(guān)代碼省略相關(guān)代碼可以看到在里面,是直接采用數(shù)組鏈表紅黑樹(shù)來(lái)實(shí)現(xiàn),時(shí)間復(fù)雜度在和之間,如果鏈表轉(zhuǎn)化為紅黑樹(shù)了,那么就是到。 在JDK1.8里面,ConcurrentHashMap在put方法里面已經(jīng)將分段鎖移除了,轉(zhuǎn)而是CAS鎖和synchronized ConcurrentHashMap是Java里面同時(shí)兼顧性能和線程安全的一個(gè)鍵值對(duì)集合,同屬于鍵值對(duì)的集合還有Hash...
摘要:我們都接觸這些集合類,這些在包的集合類就都是快速失敗的而包下的類都是安全失敗,比如。安全失敗明白了什么是快速失敗之后,安全失敗也是非常好理解的。最后說(shuō)明一下,快速失敗和安全失敗是對(duì)迭代器而言的。 什么是快速失?。╢ail-fast)和安全失?。╢ail-safe)?它們又和什么內(nèi)容有關(guān)系。以上兩點(diǎn)就是這篇文章的內(nèi)容,廢話不多話,正文請(qǐng)慢用。 我們都接觸 HashMap、ArrayLis...
摘要:和的區(qū)別和的區(qū)別是,在操作的方法上加入關(guān)鍵字,使得線程安全。使用進(jìn)行比較,或者傳入的比較器?;?,它自己的任務(wù)主要是維護(hù)保持順序的雙向鏈表。和的區(qū)別提供了一個(gè)高效的線程安全的訪問(wèn)和更新的方式。在中的過(guò)程和類似。 HashTable和HashMap的區(qū)別 HashTable和HashMap的區(qū)別是,HashTable在操作table的方法上加入synchronized關(guān)鍵字,使得線程安全...
閱讀 2070·2021-11-23 09:51
閱讀 3364·2021-09-28 09:36
閱讀 1138·2021-09-08 09:35
閱讀 1783·2021-07-23 10:23
閱讀 3279·2019-08-30 15:54
閱讀 3014·2019-08-29 17:05
閱讀 451·2019-08-29 13:23
閱讀 1307·2019-08-28 17:51