摘要:發(fā)生了線程不安全情況。本來在中,發(fā)生哈希沖突是可以用鏈表法或者紅黑樹來解決的,但是在多線程中,可能就直接給覆蓋了。中,當(dāng)同一個(gè)值上元素的鏈表節(jié)點(diǎn)數(shù)不小于時(shí),將不再以單鏈表的形式存儲(chǔ)了,會(huì)被調(diào)整成一顆紅黑樹。
List 和 Set 的區(qū)別
List , Set 都是繼承自 Collection 接口 List 特點(diǎn):元素有放入順序,元素可重復(fù) ,
Set 特點(diǎn):元素?zé)o放入順序,元素不可重復(fù),重復(fù)元素會(huì)覆蓋掉,(元素雖然無放入順序,但是元素在set中的位 置是有該元素的 HashCode 決定的,其位置其實(shí)是固定的,加入Set 的 Object 必須定義 equals ()方法 ,另外list 支持for循環(huán),也就是通過下標(biāo)來遍歷,也可以用迭代器,但是set只能用迭代,因?yàn)樗麩o序,無法用下標(biāo)來取得想 要的值。) Set和List對(duì)比 Set:檢索元素效率低下,刪除和插入效率高,插入和刪除不會(huì)引起元素位置改變。
List:和數(shù)組類似,List可以動(dòng)態(tài)增長(zhǎng),查找元素效率高,插入刪除元素效率低,因?yàn)闀?huì)引起其他元素位置改變
HashSet 是如何保證不重復(fù)的
向 HashSet 中 add ()元素時(shí),判斷元素是否存在的依據(jù),不僅要比較hash值,同時(shí)還要結(jié)合 equles 方法比較。 HashSet 中的 add ()方法會(huì)使用 HashMap 的 add ()方法。以下是 HashSet 部分源碼:
HashMap 的 key 是唯一的,由上面的代碼可以看出 HashSet 添加進(jìn)去的值就是作為 HashMap 的key。所以不會(huì) 重復(fù)( HashMap 比較key是否相等是先比較 hashcode 在比較 equals )。
HashMap 是線程安全的嗎,為什么不是線程安全的(最好畫圖說明多線程 環(huán)境下不安全)?
不是線程安全的;
如果有兩個(gè)線程A和B,都進(jìn)行插入數(shù)據(jù),剛好這兩條不同的數(shù)據(jù)經(jīng)過哈希計(jì)算后得到的哈希碼是一樣的,且該位 置還沒有其他的數(shù)據(jù)。所以這兩個(gè)線程都會(huì)進(jìn)入我在上面標(biāo)記為1的代碼中。假設(shè)一種情況,線程A通過if判斷,該 位置沒有哈希沖突,進(jìn)入了if語句,還沒有進(jìn)行數(shù)據(jù)插入,這時(shí)候 CPU 就把資源讓給了線程B,線程A停在了if語句 里面,線程B判斷該位置沒有哈希沖突(線程A的數(shù)據(jù)還沒插入),也進(jìn)入了if語句,線程B執(zhí)行完后,輪到線程A執(zhí) 行,現(xiàn)在線程A直接在該位置插入而不用再判斷。這時(shí)候,你會(huì)發(fā)現(xiàn)線程A把線程B插入的數(shù)據(jù)給覆蓋了。發(fā)生了線 程不安全情況。本來在 HashMap 中,發(fā)生哈希沖突是可以用鏈表法或者紅黑樹來解決的,但是在多線程中,可能 就直接給覆蓋了。
上面所說的是一個(gè)圖來解釋可能更加直觀。如下面所示,兩個(gè)線程在同一個(gè)位置添加數(shù)據(jù),后面添加的數(shù)據(jù)就覆蓋 住了前面添加的。
如果上述插入是插入到鏈表上,如兩個(gè)線程都在遍歷到最后一個(gè)節(jié)點(diǎn),都要在最后添加一個(gè)數(shù)據(jù),那么后面添加數(shù) 據(jù)的線程就會(huì)把前面添加的數(shù)據(jù)給覆蓋住。則
在擴(kuò)容的時(shí)候也可能會(huì)導(dǎo)致數(shù)據(jù)不一致,因?yàn)閿U(kuò)容是從一個(gè)數(shù)組拷貝到另外一個(gè)數(shù)組。
HashMap 的擴(kuò)容過程
當(dāng)向容器添加元素的時(shí)候,會(huì)判斷當(dāng)前容器的元素個(gè)數(shù),如果大于等于閾值(知道這個(gè)閾字怎么念嗎?不念 fa 值, 念 yu 值四聲)---即當(dāng)前數(shù)組的長(zhǎng)度乘以加載因子的值的時(shí)候,就要自動(dòng)擴(kuò)容啦。
擴(kuò)容( resize )就是重新計(jì)算容量,向 HashMap 對(duì)象里不停的添加元素,而 HashMap 對(duì)象內(nèi)部的數(shù)組無法裝載更 多的元素時(shí),對(duì)象就需要擴(kuò)大數(shù)組的長(zhǎng)度,以便能裝入更多的元素。當(dāng)然 Java 里的數(shù)組是無法自動(dòng)擴(kuò)容的,方法 是使用一個(gè)新的數(shù)組代替已有的容量小的數(shù)組,就像我們用一個(gè)小桶裝水,如果想裝更多的水,就得換大水桶。
HashMap hashMap=new HashMap(cap);
cap =3, hashMap 的容量為4;
cap =4, hashMap 的容量為4;
cap =5, hashMap 的容量為8;
cap =9, hashMap 的容量為16;
如果 cap 是2的n次方,則容量為 cap ,否則為大于 cap 的第一個(gè)2的n次方的數(shù)。
HashMap 1.7 與 1.8 的 區(qū)別,說明 1.8 做了哪些優(yōu)化,如何優(yōu)化的?
HashMap結(jié)構(gòu)圖
在 JDK1.7 及之前的版本中, HashMap 又叫散列鏈表:基于一個(gè)數(shù)組以及多個(gè)鏈表的實(shí)現(xiàn),hash值沖突的時(shí)候, 就將對(duì)應(yīng)節(jié)點(diǎn)以鏈表的形式存儲(chǔ)。
JDK1.8 中,當(dāng)同一個(gè)hash值( Table 上元素)的鏈表節(jié)點(diǎn)數(shù)不小于8時(shí),將不再以單鏈表的形式存儲(chǔ)了,會(huì)被 調(diào)整成一顆紅黑樹。這就是 JDK7 與 JDK8 中 HashMap 實(shí)現(xiàn)的最大區(qū)別。
其下基于 JDK1.7.0_80 與 JDK1.8.0_66 做的分析
JDK1.7中
使用一個(gè) Entry 數(shù)組來存儲(chǔ)數(shù)據(jù),用key的 hashcode 取模來決定key會(huì)被放到數(shù)組里的位置,如果 hashcode 相 同,或者 hashcode 取模后的結(jié)果相同( hash collision ),那么這些 key 會(huì)被定位到 Entry 數(shù)組的同一個(gè) 格子里,這些 key 會(huì)形成一個(gè)鏈表。
在 hashcode 特別差的情況下,比方說所有key的 hashcode 都相同,這個(gè)鏈表可能會(huì)很長(zhǎng),那么 put/get 操作 都可能需要遍歷這個(gè)鏈表,也就是說時(shí)間復(fù)雜度在最差情況下會(huì)退化到 O(n)
JDK1.8中
使用一個(gè) Node 數(shù)組來存儲(chǔ)數(shù)據(jù),但這個(gè) Node 可能是鏈表結(jié)構(gòu),也可能是紅黑樹結(jié)構(gòu)
如果插入的 key 的 hashcode 相同,那么這些key也會(huì)被定位到 Node 數(shù)組的同一個(gè)格子里。
如果同一個(gè)格子里的key不超過8個(gè),使用鏈表結(jié)構(gòu)存儲(chǔ)。
如果超過了8個(gè),那么會(huì)調(diào)用 treeifyBin 函數(shù),將鏈表轉(zhuǎn)換為紅黑樹。
那么即使 hashcode 完全相同,由于紅黑樹的特點(diǎn),查找某個(gè)特定元素,也只需要O(log n)的開銷
也就是說put/get的操作的時(shí)間復(fù)雜度最差只有 O(log n) 聽起來挺不錯(cuò),但是真正想要利用 JDK1.8 的好處,有一個(gè)限制: key的對(duì)象,必須正確的實(shí)現(xiàn)了 Compare 接口 如果沒有實(shí)現(xiàn) Compare 接口,或者實(shí)現(xiàn)得不正確(比方說所有 Compare 方法都返回0) 那 JDK1.8 的 HashMap 其實(shí)還是慢于 JDK1.7 的
簡(jiǎn)單的測(cè)試數(shù)據(jù)如下:
向 HashMap 中 put/get 1w 條 hashcode 相同的對(duì)象 JDK1.7: put 0.26s , get 0.55s JDK1.8 (未實(shí)現(xiàn) Compare 接口): put 0.92s , get 2.1s 但是如果正確的實(shí)現(xiàn)了 Compare 接口,那么 JDK1.8 中的 HashMap 的性能有巨大提升,這次 put/get 100W條 hashcode 相同的對(duì)象 JDK1.8 (正確實(shí)現(xiàn) Compare 接口,): put/get 大概開銷都在320 ms 左右
final finally finalize final
可以修飾類、變量、方法,修飾類表示該類不能被繼承、修飾方法表示該方法不能被重寫、修飾變量表 示該變量是一個(gè)常量不能被重新賦值。
finally一般作用在try-catch代碼塊中,在處理異常的時(shí)候,通常我們將一定要執(zhí)行的代碼方法finally代碼塊 中,表示不管是否出現(xiàn)異常,該代碼塊都會(huì)執(zhí)行,一般用來存放一些關(guān)閉資源的代碼。
finalize是一個(gè)方法,屬于Object類的一個(gè)方法,而Object類是所有類的父類,該方法一般由垃圾回收器來調(diào) 用,當(dāng)我們調(diào)用 System.gc() 方法的時(shí)候,由垃圾回收器調(diào)用finalize(),回收垃圾,一個(gè)對(duì)象是否可回收的 最后判斷。
感謝你耐心看完了文章…
關(guān)注作者,我會(huì)不定期在思否分享Java,Spring,MyBatis,Redis,Netty源碼分析,高并發(fā)、高性能、分布式、微服務(wù)架構(gòu)的原理,JVM性能優(yōu)化、分布式架構(gòu),BATJ面試 等資料…
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/74572.html
摘要:另外,還可以調(diào)用和等很便利的方法,以返回表示字段,方法,以及構(gòu)造器的對(duì)象的數(shù)組。運(yùn)行結(jié)果無參構(gòu)造器有參構(gòu)造器和實(shí)現(xiàn)原理和區(qū)別和區(qū)別是一個(gè)集合接口。 對(duì)象的四種引用 強(qiáng)引用只要引用存在,垃圾回收器永遠(yuǎn)不會(huì)回收 showImg(https://segmentfault.com/img/bVbsYsz?w=652&h=52); 可直接通過obj取得對(duì)應(yīng)的對(duì)象 如 obj.equels(new...
摘要:但在的過程中過程中有可能被其他對(duì)象調(diào)用它的產(chǎn)生異常,如果你的程序不捕獲這個(gè)異常,線程就會(huì)異常終止,進(jìn)入狀態(tài),如果你的程序捕獲了這個(gè)異常,那么程序就會(huì)繼續(xù)執(zhí)行語句塊可能還有語句塊以及以后的代碼。 LinkedHashMap 的應(yīng)用 基于 LinkedHashMap 的訪問順序的特點(diǎn),可構(gòu)造一個(gè) LRU(Least Recently Used) 最近最少使用簡(jiǎn)單緩存。 也有一些開源的緩存產(chǎn)...
摘要:獲取的對(duì)象范圍方法獲取的是最終應(yīng)用在元素上的所有屬性對(duì)象即使沒有代碼,也會(huì)把默認(rèn)的祖宗八代都顯示出來而只能獲取元素屬性中的樣式。因此對(duì)于一個(gè)光禿禿的元素,方法返回對(duì)象中屬性值如果有就是據(jù)我測(cè)試不同環(huán)境結(jié)果可能有差異而就是。 花了很長(zhǎng)時(shí)間整理的前端面試資源,喜歡請(qǐng)大家不要吝嗇star~ 別只收藏,點(diǎn)個(gè)贊,點(diǎn)個(gè)star再走哈~ 持續(xù)更新中……,可以關(guān)注下github 項(xiàng)目地址 https:...
摘要:好不容易在月號(hào)這天中午點(diǎn)左右接到了來自阿里的面試電話。這里會(huì)不斷收集和更新基礎(chǔ)相關(guān)的面試題,目前已收集題。面試重難點(diǎn)的和的打包過程多線程機(jī)制機(jī)制系統(tǒng)啟動(dòng)過程,啟動(dòng)過程等等掃清面試障礙最新面試經(jīng)驗(yàn)分享,此為第一篇,開篇。 2016 年末,騰訊,百度,華為,搜狗和滴滴面試題匯總 2016 年未,騰訊,百度,華為,搜狗和滴滴面試題匯總 各大公司 Java 后端開發(fā)面試題總結(jié) 各大公司 Jav...
閱讀 3106·2021-11-24 10:34
閱讀 3351·2021-11-22 13:53
閱讀 2657·2021-11-22 12:03
閱讀 3624·2021-09-26 09:47
閱讀 3033·2021-09-23 11:21
閱讀 4871·2021-09-22 15:08
閱讀 3340·2021-07-23 10:59
閱讀 1285·2019-08-29 18:31