成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

HashMap,Hashtable,ConcurrentHashMap-創(chuàng)新互聯(lián)

目錄

創(chuàng)新互聯(lián)成立于2013年,我們提供高端成都網(wǎng)站建設(shè)網(wǎng)站制作、網(wǎng)站設(shè)計、網(wǎng)站定制、成都營銷網(wǎng)站建設(shè)微信小程序開發(fā)、微信公眾號開發(fā)、成都網(wǎng)站推廣服務(wù),提供專業(yè)營銷思路、內(nèi)容策劃、視覺設(shè)計、程序開發(fā)來完成項目落地,為成都發(fā)電機租賃企業(yè)提供源源不斷的流量和訂單咨詢。

一、多線程使用HashMap的一些線程安全問題

①造成數(shù)據(jù)新增丟失

②擴容時候,造成鏈表成環(huán)

二、Hashtable和HashMap的區(qū)別?

①核心方法加鎖

②其他語法上面的略微差異?

三、引入ConcurrentHashMap【重要】

①ConcurrentHashMap相比于Hashtable的優(yōu)勢

Hashtable的缺點:

ConcurrentHashMap的一些優(yōu)化措施(jdk1.8往后)

(1)每一個哈希桶,都是一把"鎖"

??編輯

(2)ConcurrentHashMap不針對get(Object key)方法加鎖

(3)ConcurrentHashMap針對部分修改操作,采用了volatile+原子的方式,讓寫的操作與不加鎖的get()方式不會產(chǎn)生鎖沖突?

(4)擴容操作的優(yōu)化


?這三種數(shù)據(jù)結(jié)構(gòu),都是對于哈希表的具體實現(xiàn)。

?有關(guān)哈希表的具體設(shè)計,我們在前面的文章當中也提到了,關(guān)于HashMap的簡單源碼分析,以及HashMap的具體的一些實現(xiàn),也在下面這兩篇文章當中提到了:

?(1條消息) HashMap簡單源碼分析_革凡成圣211的博客-博客https://blog.csdn.net/weixin_56738054/article/details/127786631?spm=1001.2014.3001.5501
(1條消息) Java的手寫簡單的哈希表_革凡成圣211的博客-博客https://blog.csdn.net/weixin_56738054/article/details/127416821?spm=1001.2014.3001.5501


下面,將重點分析,多線程使用HashMap的一些問題,以及Hashtable、ConcurrentHashMap和HashMap之間的一些區(qū)別。


一、多線程使用HashMap的一些線程安全問題 ? ? ?①造成數(shù)據(jù)新增丟失

? 因為HashMap當中,并沒有涉及任何的加鎖操作,因此:當多個線程同時調(diào)用put()的時候,有可能在兩個鍵的哈希值一樣的時候,之后調(diào)用put()的線程新增的值覆蓋掉最開始線程新增的值。

? 圖解:

??


②擴容時候,造成鏈表成環(huán)

?我們了解到,擴容的操作,實際上是HashMap重現(xiàn)初始化一個原來大小2倍的數(shù)組,并且根據(jù)新的數(shù)組的長度,重新哈希的這樣一個過程。

? 如果執(zhí)行并發(fā)擴容,那么,很有可能在擴容的時候,讓哈希表當中某一個哈希桶的鏈表變成了一個"環(huán)"。那么,也就意味著如果想獲取某一個元素,對哈希桶對應(yīng)位置的鏈表進行遍歷的時候,沒有任何一個節(jié)點的next指針為null,那么將引發(fā)死循環(huán)。


二、Hashtable和HashMap的區(qū)別? ? ? ? ①核心方法加鎖

? Hashtable的核心方法put()和get()方法被加鎖了。因此,Hashtable是線程安全的

??


②其他語法上面的略微差異?

?(1)HashMap允許null值作為鍵和值,而Hashtable不允許null作為鍵和值。

?(2)添加值的哈希算法不同,對于HashMap來說,添加值的哈希算法采用的是內(nèi)部自定義的一個哈希算法,而Hashtable采用的直接是key.hash()的方式計算出的哈希值。但是負載因子都是0.75.

?(3)初始化的容量不同:HashMap的默認初始容量為16,而Hashtable默認的初始容量為11.

?(4)擴容的方式不同:HashMap采用的是2倍大小的方式擴容,而Hashtable擴容的規(guī)則為當前容量*2+1.

?...這些差異,羅列一部分即可,最重要的還是多線程和單線程的使用環(huán)境區(qū)別。


三、引入ConcurrentHashMap【重要】 ①ConcurrentHashMap相比于Hashtable的優(yōu)勢

對于Hashtable來說,它解決線程安全問題的方式,比較"粗魯”。

Hashtable的缺點:

?第一:

?Hashtable使用的直接是synchronized修飾核心方法的方式來加鎖的,那么,如果兩個線程同時只是讀取某一個變量的值,根據(jù)之前對線程安全問題的概述,如果線程僅僅只是對變量進行讀操作而并非寫操作,那么并不會發(fā)生線程安全問題。

?但是Hashtable即使是在多個線程同時讀取某個Entry的值的時候,也照樣會造成阻塞等待的情況,因此Hashtable的鎖的粒度是比較大的。


?第二:

?即使是put()、get()操作,發(fā)生線程安全問題的前提條件也必須是需要put()的兩個鍵的哈希值相同的情況,也就是,針對同一個哈希桶進行put()或者get()的情況。

?而Hashtable采用的是直接“一棒打死”。無論是否針對同一個哈希桶進行讀寫操作,只要多個線程同時調(diào)用一個map的put()或者get()方法,都會發(fā)生阻塞等待的情況。


ConcurrentHashMap的一些優(yōu)化措施(jdk1.8往后) ? ? ?(1)每一個哈希桶,都是一把"鎖"

?讓每一個哈希桶都是一把鎖。當新增元素發(fā)生哈希沖突,也就是散列到同一個哈希地址的時候,才會發(fā)生鎖沖突。

?這樣,就有效減少了不必要的鎖沖突,減小了鎖的粒度

?

觀察上面的圖:當兩個線程同時嘗試分別修改同一個哈希地址的1,2節(jié)點的時候,會產(chǎn)生阻塞等待的情況。

當兩個線程同時修改3,4節(jié)點的時候,不會產(chǎn)生阻塞等待。

也就是,只有發(fā)生了哈希沖突的時候,才會產(chǎn)生阻塞等待的情況?

觀察一下源碼:

?


??對于jdk1.8之前的代碼,是采用分段鎖的方式進行修改的。也就是,其中的N個哈希桶作為一把鎖,如果有線程同時針對這N個為一把鎖的哈希桶進行修改操作,會產(chǎn)生鎖沖突,造成阻塞等待。


(2)ConcurrentHashMap不針對get(Object key)方法加鎖

由于get()方法是通過key得到對應(yīng)的value的值的方法,本質(zhì)上是“讀取”操作,當多個線程同時調(diào)用get()方法的時候,不存在線程安全問題。

因此,ConcurrentHashMap取消了對于get()方法加鎖的機制。

?

這里需要注意的地方是,ConcurrentHashmap當中:

? Ⅰ一個線程讀去數(shù)據(jù),另外一個線程也同時去讀取數(shù)據(jù),這個時候不存在線程安全問題,也不存在鎖沖突;因為ConcurrentHashMap沒有針對get方法加鎖

? Ⅱ一個線程去寫數(shù)據(jù),另外一個線程也去寫數(shù)據(jù),不存在線程安全問題,但是有可能存在鎖沖突;存在鎖沖突的前提是兩個線程針對同一個哈希桶進行寫操作。

? Ⅲ一個線程去讀數(shù)據(jù),另外一個線程去寫數(shù)據(jù),不存在線程安全問題,但是有可能產(chǎn)生鎖沖突。

??對于第Ⅲ點,如果產(chǎn)生了鎖沖突,那么就是意味著兩個線程一個對于同一哈希桶進行"讀"操作,另外一個針對哈希桶進行"寫"操作,并且都是哈希桶有存放元素,也就是需要遍歷的時候,才會產(chǎn)生鎖沖突。

? 如果哈希桶沒有存放元素,是null的,那么,請往下面第(3)點查看。


(3)ConcurrentHashMap針對部分修改操作,采用了volatile+原子的方式,讓寫的操作變?yōu)?原子"的,從而與不加鎖的讀操作不會產(chǎn)生鎖沖突?

?ConcurrentHashMap內(nèi)部充分利用了CAS,來削減了加鎖的次數(shù)。

?下面,舉幾個例子,關(guān)于ConcurrentHashMap是如何使用CAS的:

? 例子1、當讓存放元素之后,個數(shù)+1的時候,采用的是CAS的做法來保證數(shù)組當中實際存儲key的數(shù)量+1這個操作的原子性

??

其中,addCount方法內(nèi)部采用的就是CAS的做法來實現(xiàn)個數(shù)+1的原子性的。?


? 例子2、?當對應(yīng)的HashEntry數(shù)組當中,某一個位置不存放任何元素,也就是為null的時候,會采用cas的方式填充到對應(yīng)的哈希地址。

?

?對于ConcurrentHashMap當中修改key的個數(shù),本質(zhì)上還是在addCount方法內(nèi)部,通過CAS的方式來修改


(4)擴容操作的優(yōu)化

?? ? ?回顧一下HashMap或者Hashtable擴容的操作,它們都是創(chuàng)建一個更大容量的數(shù)組,然后把每一個元素重新哈希的做法。

? 在數(shù)據(jù)量比較大的時候,會造成可能某次put()之后,線程會阻塞等待很長的時間,才可以完成擴容。

?擴容條件:

?①當存放Node節(jié)點的數(shù)組長度小于64,并且單個哈希桶的鏈表的存放節(jié)點個數(shù)達到8的時候,會觸發(fā)擴容;如果存放節(jié)點的數(shù)組長度>=64,那么會把當前的鏈表樹化為紅黑樹。

?②當存儲的實際key的數(shù)量/Node數(shù)組的長度達到負載因子的時候,會觸發(fā)擴容


以上兩點,和jdk1.8版本的HashMap的擴容前提條件類似,沒有太大的差別。

滿足上面的條件之后,會進入到下面的操作:

首先申請一個原來數(shù)組大小2倍的新數(shù)組

如果有多個線程同時嘗試擴容,那么,ConcurrentHashMap會對這些線程進行"分工”。何為分工呢?畫個圖簡單看一看:

?也就是,每一個線程,分別對原有的數(shù)組上面的元素分別進行"搬運"操作,讓它們都被各自的線程重新哈希到新的數(shù)組上面的位置,這樣的效率會更加的高。


? 同時,如果ConcurrentHashMap如果正在擴容的時候:

? 其他線程調(diào)用get方法,那么調(diào)用的線程會查詢舊數(shù)組和新的數(shù)組當中是否存在對應(yīng)的key。

? 其他線程如果調(diào)用remove方法,那么調(diào)用的線程會把舊數(shù)組和新的數(shù)組當中的key都刪除掉。

? 而不是一直阻塞等待,直到擴容執(zhí)行完畢。


??

你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧

文章名稱:HashMap,Hashtable,ConcurrentHashMap-創(chuàng)新互聯(lián)
URL分享:http://jinyejixie.com/article18/eigdp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供用戶體驗、域名注冊、網(wǎng)站內(nèi)鏈電子商務(wù)、網(wǎng)站維護、網(wǎng)站設(shè)計

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都定制網(wǎng)站網(wǎng)頁設(shè)計
花莲市| 柘城县| 河津市| 林周县| 镇沅| 马关县| 武功县| 教育| 石景山区| 舒兰市| 札达县| 邛崃市| 济源市| 安新县| 丽江市| 公主岭市| 司法| 安陆市| 镇沅| 瑞金市| 宜良县| 监利县| 旬阳县| 芜湖市| 古蔺县| 巴中市| 天气| 韶山市| 金秀| 桐城市| 安国市| 巴彦县| 万年县| 微山县| 饶阳县| 蓝田县| 建水县| 罗江县| 临海市| 和田县| 吴川市|