jdk1.7與jdk1.8中HashMap區(qū)別
JDK7,HashMap的結(jié)構(gòu)很簡(jiǎn)單挚赊,基于一個(gè)數(shù)組以及多個(gè)鏈表的實(shí)現(xiàn)诡壁,hash值沖突的時(shí)候,就將對(duì)應(yīng)節(jié)點(diǎn)以鏈表的形式存儲(chǔ)荠割。這樣子的HashMap性能上就有問(wèn)題了妹卿,如果有成百上千個(gè)節(jié)點(diǎn)在hash時(shí)發(fā)生碰撞,存儲(chǔ)一個(gè)鏈表中蔑鹦,那么如果要查找其中一個(gè)節(jié)點(diǎn)夺克,就會(huì)花很長(zhǎng)的時(shí)間,從而導(dǎo)致性能損失嚎朽。
JDK8中采用的數(shù)組+鏈表+紅黑樹(shù)結(jié)構(gòu)的方式铺纽,也是非線(xiàn)程安全的。當(dāng)某個(gè)位桶的鏈表的長(zhǎng)度達(dá)到某個(gè)閥值的時(shí)候哟忍,這個(gè)鏈表就將轉(zhuǎn)換成紅黑樹(shù)狡门。
插入鍵值對(duì)的put方法的區(qū)別,1.8中會(huì)將節(jié)點(diǎn)插入到鏈表尾部锅很,而1.7中是采用頭插其馏。
?擴(kuò)容策略:1.7中是只要不小于閾值就直接擴(kuò)容2倍;而1.8的擴(kuò)容策略會(huì)更優(yōu)化爆安,當(dāng)數(shù)組容量未達(dá)到64時(shí)叛复,以2倍進(jìn)行擴(kuò)容,超過(guò)64之后若桶中元素個(gè)數(shù)不小于7就將鏈表轉(zhuǎn)換為紅黑樹(shù)扔仓,但如果紅黑樹(shù)中的元素個(gè)數(shù)小于6就會(huì)還原為鏈表致扯,當(dāng)紅黑樹(shù)中元素不小于32的時(shí)候才會(huì)再次擴(kuò)容。
之所以鏈表要轉(zhuǎn)成紅黑樹(shù)当辐,還是為了解決存取效率的問(wèn)題。鏈表過(guò)長(zhǎng)鲤看,取數(shù)據(jù)的效率就很慢缘揪,紅黑樹(shù)插入比較慢,但取數(shù)據(jù)還是很快的。
答案:
正常情況下? hashmap 在保存數(shù)據(jù)時(shí)找筝,底層是數(shù)組+鏈表+紅黑樹(shù)? 但是 你去源碼中看時(shí)蹈垢,發(fā)現(xiàn)子啊hashMap 底層沒(méi)有加任何的多線(xiàn)程中的鎖機(jī)制,比如:?synchronize修飾? 袖裕,所以在多線(xiàn)程的情況下? hashMap 的單項(xiàng)鏈表曹抬,可能會(huì)變成一個(gè)環(huán)形的鏈表,所以這個(gè)鏈表上的Next元素的指向永遠(yuǎn)不為null, 所以在遍歷的時(shí)候就是死循環(huán)啊急鳄。
HashMap是線(xiàn)程不安全的谤民,其主要體現(xiàn):
#1.在jdk1.7中,在多線(xiàn)程環(huán)境下疾宏,擴(kuò)容時(shí)會(huì)造成環(huán)形鏈或數(shù)據(jù)丟失张足。
#2.在jdk1.8中,在多線(xiàn)程環(huán)境下坎藐,會(huì)發(fā)生數(shù)據(jù)覆蓋的情況为牍。
1HashMap在put的時(shí)候,插入的元素超過(guò)了容量(由負(fù)載因子決定)的范圍就會(huì)觸發(fā)擴(kuò)容操作岩馍,就是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),所以HashMap是線(xiàn)程不安全的
2 HashMap底層是一個(gè)Entry數(shù)組佃乘,當(dāng)發(fā)生hash沖突的時(shí)候囱井,hashmap是采用鏈表的方式來(lái)解決的,在對(duì)應(yīng)的數(shù)組位置存放鏈表的頭結(jié)點(diǎn)趣避。對(duì)鏈表而言庞呕,新加入的節(jié)點(diǎn)會(huì)從頭結(jié)點(diǎn)加入。在hashmap做put操作的時(shí)候會(huì)調(diào)用到以上的方法〕膛粒現(xiàn)在假如A線(xiàn)程和B線(xiàn)程同時(shí)對(duì)同一個(gè)數(shù)組位置調(diào)用addEntry住练,兩個(gè)線(xiàn)程會(huì)同時(shí)得到現(xiàn)在的頭結(jié)點(diǎn),然后A寫(xiě)入新的頭結(jié)點(diǎn)之后愁拭,B也寫(xiě)入新的頭結(jié)點(diǎn)讲逛,那B的寫(xiě)入操作就會(huì)覆蓋A的寫(xiě)入操作造成A的寫(xiě)入操作丟失
ConcurrentHashMap:在hashMap的基礎(chǔ)上,ConcurrentHashMap將數(shù)據(jù)分為多個(gè)segment岭埠,默認(rèn)16個(gè)盏混,然后每次操作對(duì)一個(gè)segment加鎖蔚鸥,避免多線(xiàn)程鎖的幾率,提高并發(fā)效率