阿粉被面試官吊起來(lái)瘋狂捶打,結(jié)果很尷尬
本文轉(zhuǎn)載自微信公眾號(hào)「Java極客技術(shù)」,作者鴨血粉絲。轉(zhuǎn)載本文請(qǐng)聯(lián)系Java極客技術(shù)公眾號(hào)。
阿粉最近接到了一個(gè)面試,但是面試結(jié)果不是很盡如人意,因?yàn)殡m然有些問(wèn)題回答的還湊活,但是因?yàn)槊嬖嚬賳?wèn)了一些后序的內(nèi)容,阿粉不會(huì),于是就被吊起來(lái)瘋狂捶打了半天,敗興而歸。
面試題1:HashMap和ConcurrentHashMap的區(qū)別
我們都知道HashMap是線程不安全的,當(dāng)我們?cè)谟胁l(fā)的情況下去使用HashMap的put,還有g(shù)et等一些方法的時(shí)候,CPU直接飆升,而且也沒(méi)有辦法保證線程的安全性,但是更加安全的HashTable呢?
因?yàn)樵贖ashTable里面put和get的方法的,沒(méi)一個(gè)都是加上了synchronize,雖然保證了線程的安全性,但是效率就比較低下了,在我們進(jìn)行并發(fā)訪問(wèn)的時(shí)候,每次只能是一個(gè)線程進(jìn)行操作,其他的線程就只能是阻塞執(zhí)行,所以,他的效率相對(duì)來(lái)說(shuō),是非常低的,這時(shí)候我們就出現(xiàn)了ConcurrentHashMap。
而ConcurrentHashMap則使用了鎖分段(減小鎖范圍)、CAS(樂(lè)觀鎖,減小上下文切換開(kāi)銷(xiāo),無(wú)阻塞)等等技術(shù),這時(shí)候你回答了,就出現(xiàn)了一環(huán)套一環(huán)的操作,那么你就分別來(lái)說(shuō)說(shuō)把。
在JDK1.7中,ConcurrentHashMap使用的鎖分段技術(shù),將數(shù)據(jù)分成一段一段的存儲(chǔ),然后給每一段數(shù)據(jù)配一把鎖,當(dāng)一個(gè)線程占用鎖訪問(wèn)其中一個(gè)段數(shù)據(jù)的時(shí)候,其他段的數(shù)據(jù)也能被其他線程訪問(wèn)。
在JDK1.8中,ConcurrentHashMap采用CAS和synchronized方式處理并發(fā)。以put操作為例,CAS方式確定key的數(shù)組下標(biāo),synchronized保證鏈表節(jié)點(diǎn)的同步效果
阿粉也沒(méi)怎么墨跡,直接說(shuō)能給我一張紙么?于是阿粉畫(huà)了一個(gè)之前在網(wǎng)上看的圖。
阿粉給面試官介紹的時(shí)候直接就從圖上介紹了,而阿粉直接分析源碼的時(shí)候,剛開(kāi)始Segment繼承了ReentrantLock的時(shí)候,面試官就打斷了我接下來(lái)要敘述的內(nèi)容,讓我直接就說(shuō)1.8的了。
1.8中的:
- 首先new一個(gè)新的hash表(nextTable)出來(lái),大小是原來(lái)的2倍。后面的rehash都是針對(duì)這個(gè)新的hash表操作,不涉及原h(huán)ash表(table)。
- 然后會(huì)對(duì)原h(huán)ash表(table)中的每個(gè)鏈表進(jìn)行rehash,此時(shí)會(huì)嘗試獲取頭節(jié)點(diǎn)的鎖。這一步就保證了在rehash的過(guò)程中不能對(duì)這個(gè)鏈表執(zhí)行put操作。
- 通過(guò)sizeCtl控制,使擴(kuò)容過(guò)程中不會(huì)new出多個(gè)新hash表來(lái)。
- 最后,將所有鍵值對(duì)重新rehash到新表(nextTable)中后,用nextTable將table替換。這就避免了HashMap中g(shù)et和擴(kuò)容并發(fā)時(shí),可能get到null的問(wèn)題。
- 在整個(gè)過(guò)程中,共享變量的存儲(chǔ)和讀取全部通過(guò)volatile或CAS的方式,保證了線程安全。
而至于分析源碼,阿粉不再進(jìn)行分析了,以后在遇到面試的時(shí)候分析源碼的時(shí)候在繼續(xù)給大家說(shuō)。畢竟下面還有很多內(nèi)容。
面試題2:你對(duì)著兩種方式的看法是什么,為什么1.8要改變呢?優(yōu)點(diǎn)是哪里呢?
阿粉就猜測(cè)到可能這么問(wèn),畢竟你開(kāi)了頭了,你都區(qū)分出1.7和1.8了,必然會(huì)有面試官會(huì)這么問(wèn)你,阿粉是這么回答的。
(1) 減少內(nèi)存開(kāi)銷(xiāo)
假設(shè)使用可重入鎖,那么每個(gè)節(jié)點(diǎn)都需要繼承AQS,但并不是每個(gè)節(jié)點(diǎn)都需要同步支持,只有鏈表的頭節(jié)點(diǎn)(紅黑樹(shù)的根節(jié)點(diǎn))需要同步,這無(wú)疑消耗巨大內(nèi)存。
(2) 獲得JVM的支持
可重入鎖畢竟是API級(jí)別的,后續(xù)的性能優(yōu)化空間很小。synchronized則是JVM直接支持的,JVM能夠在運(yùn)行時(shí)作出相應(yīng)的優(yōu)化措施:鎖粗化、鎖消除、鎖自旋等等。使得synchronized能夠隨著JDK版本的升級(jí)而不改動(dòng)代碼的前提下獲得性能上的提升。
也是虧了阿粉在面試之前的時(shí)候看過(guò)很多這樣的文章,很多東西都專(zhuān)門(mén)去比對(duì)了一下,于是第二個(gè)問(wèn)題結(jié)束了。
面試題3:你們是怎么避免 SQL 注入的?
阿粉看到這個(gè)問(wèn)題的時(shí)候,第一反應(yīng)就是肯定是按照我簡(jiǎn)歷上寫(xiě)的問(wèn)的,因?yàn)榘⒎壑暗墓揪褪菍?duì)安全性要求比較高的,像什么SQL注入啦,像跨站攻擊啦,于是阿粉就開(kāi)始說(shuō)了。
阿粉在之前的時(shí)候時(shí)候最多使用的是 where條件后面加上個(gè)1=1然后再繼續(xù)寫(xiě)自己的參數(shù)。
- 確認(rèn)每種數(shù)據(jù)的類(lèi)型,比如是數(shù)字,數(shù)據(jù)庫(kù)則必須使用int類(lèi)型來(lái)存儲(chǔ)
- 嚴(yán)格限制數(shù)據(jù)庫(kù)權(quán)限
- 過(guò)濾參數(shù)中含有的一些數(shù)據(jù)庫(kù)關(guān)鍵詞
比如說(shuō)過(guò)濾一些 and,char,這些在數(shù)據(jù)庫(kù)語(yǔ)句中是關(guān)鍵字的一些詞。
也可能面試官對(duì)這些數(shù)據(jù)安全的方面不是太注重,所以,阿粉回答出這幾種方式之后,就已經(jīng)算是完事了,也沒(méi)有繼續(xù)再往下深究。
面試題4:說(shuō)一下 MySQL常用的引擎都有哪些?
數(shù)據(jù)庫(kù)存儲(chǔ)引擎是數(shù)據(jù)庫(kù)底層軟件組織,數(shù)據(jù)庫(kù)管理系統(tǒng)(DBMS)使用數(shù)據(jù)引擎進(jìn)行創(chuàng)建、查詢(xún)、更新和刪除數(shù)據(jù)。不同的存儲(chǔ)引擎提供不同的存儲(chǔ)機(jī)制、索引技巧、鎖定水平等功能,使用不同的存儲(chǔ)引擎,還可以 獲得特定的功能?,F(xiàn)在許多不同的數(shù)據(jù)庫(kù)管理系統(tǒng)都支持多種不同的數(shù)據(jù)引擎。存儲(chǔ)引擎主要有:1. MyIsam , 2. InnoDB, 3. Memory, 4. Archive, 5. Federated 。
關(guān)于這個(gè)阿粉就不再給大家說(shuō)了,給大家安排上幾張圖:
面試題5:看你簡(jiǎn)歷上說(shuō)用過(guò)redis,那么你說(shuō)一下redis的持久化的方式吧。
- RDB持久化方式能夠在指定的時(shí)間間隔能對(duì)你的數(shù)據(jù)進(jìn)行快照存儲(chǔ).
- AOF持久化方式記錄每次對(duì)服務(wù)器寫(xiě)的操作,當(dāng)服務(wù)器重啟的時(shí)候會(huì)重新執(zhí)行這些命令來(lái)恢復(fù)原始的數(shù)據(jù),AOF命令以redis協(xié)議追加保存每次寫(xiě)的操作到文件末尾.Redis還能對(duì)AOF文件進(jìn)行后臺(tái)重寫(xiě),使得AOF文件的體積不至于過(guò)大.
RDB其實(shí)就是把數(shù)據(jù)以快照的形式保存在磁盤(pán)上。什么是快照呢,你可以理解成把當(dāng)前時(shí)刻的數(shù)據(jù)拍成一張照片保存下來(lái)。
RDB持久化是指在指定的時(shí)間間隔內(nèi)將內(nèi)存中的數(shù)據(jù)集快照寫(xiě)入磁盤(pán)。也是默認(rèn)的持久化方式,這種方式是就是將內(nèi)存中數(shù)據(jù)以快照的方式寫(xiě)入到二進(jìn)制文件中,默認(rèn)的文件名為dump.rdb。
而關(guān)于怎么觸發(fā),這個(gè)就直接去修改redis.conf配置文件即可。
AOF持久化,實(shí)際上就是追加保存每次寫(xiě)的操作到文件末尾,也可能阿粉在實(shí)際的使用Redis的時(shí)候,并沒(méi)有去做過(guò)持久化的操作,回答到這里已經(jīng)算是沒(méi)有其他的了,而接下來(lái)面試官問(wèn)的幾個(gè)關(guān)于Redis的問(wèn)題就回答不是特別的好了,所以在Redis上面,還是得下功夫呀。
面試題6:JVM的內(nèi)存結(jié)構(gòu),還有就是不同代的算法。
阿粉在之前的文章已經(jīng)算是分析的非常的透徹了,所以在這里阿粉就把之前的鏈接送上,大家可以看一下。
面試的時(shí)候按照這個(gè)套路回答 Java GC 的相關(guān)問(wèn)題一定能過(guò)!