emm...
HashMap的源碼懈费,實(shí)現(xiàn)原理锌钮,JDK8中對(duì)HashMap做了怎樣的優(yōu)化告希。
數(shù)組:數(shù)組存儲(chǔ)區(qū)間是連續(xù)的扑浸,占用內(nèi)存嚴(yán)重,故空間復(fù)雜的很大燕偶。但數(shù)組的二分查找時(shí)間復(fù)雜度小喝噪,為O(1);數(shù)組的特點(diǎn)是:尋址容易指么,插入和刪除困難酝惧;
鏈表:鏈表存儲(chǔ)區(qū)間離散,占用內(nèi)存比較寬松伯诬,故空間復(fù)雜度很小晚唇,但時(shí)間復(fù)雜度很大,達(dá)O(N)盗似。鏈表的特點(diǎn)是:尋址困難哩陕,插入和刪除容易。
哈希表:那么我們能不能綜合兩者的特性赫舒,做出一種尋址容易悍及,插入刪除也容易的數(shù)據(jù)結(jié)構(gòu),這就是我們要提起的哈希表接癌。哈希表((Hash table)既滿足了數(shù)據(jù)的查找方便心赶,同時(shí)不占用太多的內(nèi)容空間,使用也十分方便缺猛。哈希表有多種不同的實(shí)現(xiàn)方法缨叫,我們可以理解為“鏈表的數(shù)組”。
哈希表是由 數(shù)組 + 鏈表
組成的荔燎,一個(gè)長(zhǎng)度為 16
的數(shù)組中耻姥,每個(gè)元素存儲(chǔ)的是一個(gè)鏈表的頭結(jié)點(diǎn)。那么這些元素是按照什么樣的規(guī)則存儲(chǔ)到數(shù)組中呢湖雹。一般情況是通過(guò) hash(key)%len
獲得咏闪,也就是元素的key的哈希值對(duì)數(shù)組長(zhǎng)度取模得到。比如上述哈希表中摔吏, 12%16=12
, 28%16=12
, 108%16=12
, 140%16=12
鸽嫂。所以 12
、 28
征讲、 108
以及 140
都存儲(chǔ)在數(shù)組下標(biāo)為 12
的位置据某。
JDK8中,HashMap 加入了紅黑樹(shù)的使用诗箍,當(dāng)節(jié)點(diǎn)長(zhǎng)度大于8并且數(shù)組的長(zhǎng)度大于64時(shí)癣籽,該節(jié)點(diǎn)鏈表就會(huì)轉(zhuǎn)化成紅黑樹(shù)。數(shù)組長(zhǎng)度小于64并且節(jié)點(diǎn)長(zhǎng)度大于8時(shí),僅僅擴(kuò)容筷狼,并不會(huì)將鏈表轉(zhuǎn)換成紅黑樹(shù)瓶籽。
相關(guān)文獻(xiàn) -> http://www.importnew.com/28263.html
HaspMap擴(kuò)容是怎樣擴(kuò)容的,為什么都是2的N次冪的大小埂材。
HashMap計(jì)算 Key
值在數(shù)組中的位置是使用 Key.hashcode()
與 數(shù)組長(zhǎng)度減一
進(jìn)行 &
運(yùn)算塑顺。當(dāng)長(zhǎng)度是 2
的N次冪時(shí),數(shù)組長(zhǎng)度減一
的二進(jìn)制實(shí)則為 N-1個(gè)1
俏险。進(jìn)行與或運(yùn)算時(shí)严拒,能夠快速取到小于自己的一個(gè)整數(shù)。比 %
取模速度更快竖独。
HashMap裤唠,HashTable,ConcurrentHashMap的區(qū)別莹痢。
HashMap是非線程安全的种蘸,HashTable是線程安全的,內(nèi)部的方法基本都經(jīng)過(guò)synchronized修飾竞膳。因?yàn)橥脚搿⒐P阅艿仍颍阅芸隙ㄊ荋ashMap更佳顶猜,因此HashTable已被淘汰。
HashMap的鍵和值都允許有null存在痘括,而HashTable則都不行长窄,在HashTable中put進(jìn)的鍵值只要有一個(gè)null,直接拋出NullPointerException纲菌。
ConcurrentHashMap是線程安全的HashMap的實(shí)現(xiàn)挠日。HashTable里使用的是synchronized關(guān)鍵字,這其實(shí)是對(duì)對(duì)象加鎖翰舌,鎖住的都是對(duì)象整體嚣潜,當(dāng)Hashtable的大小增加到一定的時(shí)候,性能會(huì)急劇下降椅贱,因?yàn)榈鷷r(shí)需要被鎖定很長(zhǎng)的時(shí)間懂算。
ConcurrentHashMap引入了分割(Segment),上面代碼中的最后一行其實(shí)就可以理解為把一個(gè)大的Map拆分成N個(gè)小的HashTable庇麦,在put方法中计技,會(huì)根據(jù)hash(paramK.hashCode())來(lái)決定具體存放進(jìn)哪個(gè)Segment,如果查看Segment的put操作山橄,我們會(huì)發(fā)現(xiàn)內(nèi)部使用的同步機(jī)制是基于lock操作的垮媒,這樣就可以對(duì)Map的一部分(Segment)進(jìn)行上鎖,這樣影響的只是將要放入同一個(gè)Segment的元素的put操作,保證同步的時(shí)候睡雇,鎖住的不是整個(gè)Map(HashTable就是這么做的)萌衬,相對(duì)于HashTable提高了多線程環(huán)境下的性能,因此HashTable已經(jīng)被淘汰了它抱。
極高并發(fā)下HashTable和ConcurrentHashMap哪個(gè)性能好秕豫,如何實(shí)現(xiàn)的。
上個(gè)問(wèn)題已經(jīng)回答了抗愁,在極高并發(fā)下ConcurrentHashMap的性能要好于HashTable馁蒂,因?yàn)镃oncurrentHashMap采用的是分段鎖,不會(huì)造成整個(gè)對(duì)象鎖住蜘腌,在高并發(fā)時(shí)性能明顯好于Hashtable沫屡。
HashMap在高并發(fā)下如果沒(méi)有處理線程安全會(huì)有怎樣的安全隱患,具體表現(xiàn)是什么撮珠。
多線程put時(shí)可能導(dǎo)致元素丟失沮脖,原因:當(dāng)多個(gè)線程同時(shí)執(zhí)行addEntry(hash,key ,value,i)時(shí),如果產(chǎn)生哈希碰撞芯急,導(dǎo)致兩個(gè)線程得到同樣的bucketIndex去存儲(chǔ)勺届,就可能會(huì)發(fā)生元素覆蓋丟失的情況
多線程put時(shí)可能會(huì)導(dǎo)致get無(wú)限循環(huán),具體表現(xiàn)為CPU使用率100%娶耍;原因:在向HashMap put元素時(shí)免姿,會(huì)檢查HashMap的容量是否足夠,如果不足榕酒,則會(huì)新建一個(gè)比原來(lái)容量大兩倍的Hash表胚膊,然后把數(shù)組從老的Hash表中遷移到新的Hash表中,遷移的過(guò)程就是一個(gè)rehash()的過(guò)程想鹰,多個(gè)線程同時(shí)操作就有可能會(huì)形成循環(huán)鏈表紊婉,所以在使用get()時(shí),就會(huì)出現(xiàn)Infinite Loop的情況辑舷。
相關(guān)文獻(xiàn) -> https://www.cnblogs.com/hunrry/p/9183027.html
java中四種修飾符的限制范圍喻犁。
private: Java語(yǔ)言中對(duì)訪問(wèn)權(quán)限限制的最窄的修飾符,一般稱之為“私有的”何缓。被其修飾的屬性以及方法只能被該類(lèi)的對(duì)象 訪問(wèn)肢础,其子類(lèi)不能訪問(wèn),更不能允許跨包訪問(wèn)碌廓。
default:即不加任何訪問(wèn)修飾符乔妈,通常稱為“默認(rèn)訪問(wèn)權(quán)限“或者“包訪問(wèn)權(quán)限”。該模式下氓皱,只允許在同一個(gè)包中進(jìn)行訪問(wèn)路召。
protected: 介于public 和 private 之間的一種訪問(wèn)修飾符勃刨,一般稱之為“保護(hù)訪問(wèn)權(quán)限”。被其修飾的屬性以及方法只能被類(lèi)本 身的方法及子類(lèi)訪問(wèn)股淡,即使子類(lèi)在不同的包中也可以訪問(wèn)身隐。
public: Java語(yǔ)言中訪問(wèn)限制最寬的修飾符,一般稱之為“公共的”。被其修飾的類(lèi)、屬性以及方法不僅可以跨類(lèi)訪問(wèn)澄暮,而且 允許跨包訪問(wèn)实檀。
Object類(lèi)中的方法略号。
clone()
clone()函數(shù)的用途是用來(lái)另存一個(gè)當(dāng)前存在的對(duì)象。
hashCode()和equals()
equals()用于確認(rèn)兩個(gè)對(duì)象是否相同,hashCode()用于獲取對(duì)象的哈希值,哈希值相同的對(duì)象不一定equals()叁巨,equale()返回true的兩個(gè)對(duì)象一定相同。
toString()
toString()返回一個(gè)String對(duì)象呐籽,用來(lái)標(biāo)識(shí)自己 锋勺。
getClass()
getClass()返回一個(gè)Class對(duì)象。因?yàn)榉祷氐氖且粋€(gè)class對(duì)象,后面可以跟class類(lèi)的方法狡蝶。用的是誰(shuí)的構(gòu)造函數(shù)庶橱,那么getClass返回的就是誰(shuí)的類(lèi)型,getClass()經(jīng)常用于java反射機(jī)制贪惹。
finalize()
這個(gè)函數(shù)在進(jìn)行垃圾回收的時(shí)候會(huì)用到苏章,匿名對(duì)象回收之前會(huì)調(diào)用到。