【面經】5年Java面試親身經驗


一、背景

自己由於某種原因,需要找下份工作,經歷了2周多時間面了20多家(按部門算),其中包括AT, TMDK等大廠,也拿到了一些offer。

整個過程特別緊湊,比較辛苦,加上裸面原因,前期表現的並不好,到后面才嫻熟了一些。

因為這樣連貫的面試車輪戰,很容易就能感受到面試的高頻知識點,對后面的面試就越來越能把握住節奏點。

寫這篇文章的目的,除了自我總結之外,也希望能對后面的年輕人有一些幫助。

二、題目列表:

每家1-3輪不等,題目太多,只能憑印象或當時做的筆記列出,其中高頻的(出現3次及以上)會以紅色標出。

備注:因為時間有限,對每個題目下的答案,僅僅是列出了腦海中的“記憶索引”,僅供參考(水平有限甚至可能還有錯誤),需要自行去學習去總結答案。

1. HashMap數據結構?put, get過程?擴容機制?JDK1.8版本中相比1.7做了哪些優化?容量怎么計算的?

hash表+鏈表+紅黑樹;先計算hashcode,再對&(n-1)計算,最后使用equals判斷;double容量擴容,並進行rehash計算,性能開銷較大;增加了紅黑樹,鏈表插入由頭插該為尾插(為了解決並發場景CPU 100%問題);直接由size屬性返回

建議:深度分析源碼,重點關注核心方法

2. ConcurrentHashMap數據結構?如何保證線程安全的?相比1.7做了什么優化?

與hashmap結構一致;使用cas保證;使用cas代替segement分段鎖,提升效率

3. 為什么String被設計成不可變的?

 設計考慮、效率考慮、安全考慮

4. 限流算法有哪些?區別是什么?令牌桶如何實現?

漏桶與令牌桶;前者保持勻速,后者能應對突發流量;使用guava的RateLimiter

 5. 一致性hash算法?

已知一個[0, 2^32-1]這樣整數的集合,從小到大按順時針均勻分布。先將機器ip(或hostname等其他唯一信息)使用某種hash算法,計算出hash值,

再對2^32取余,定位到環中的某個位置。再對key進行hash計算,對2^32取余,定位到某個位置后,按順時針找到第一個機器的位置,這樣就找到了key與機器的映射關系。

為了解決機器數量過小,會有數據不平衡的問題,可以再建立虛擬節點,如針對172.23.23.23建立172.23.23.23#1, 172.23.23.23#2, 172.23.23.23#3 這樣3個虛擬節點,再做同樣的操作 

6.  JVM內存模型(有些面試官其實只是讓你回答內存布局)?各個內存區域分別是做什么的?有哪些是共享的?

每個線程有獨立的內存,互相是隔離的,讀變量時會從主內存讀取放到線程內存中,做完計算后,會“異步”的寫回主內存;

虛擬機棧用於保存變量引用,此處省略...

建議:JMM這塊知識,有很多細節,涉及happens-before原則,內存屏障等很多概念的東西,能理解就去理解下

7. 年輕代,老年代區別?垃圾回收算法分別是?垃圾回收器有哪些?

前者保存小或生命周期短的對象,后者保存大或生命周期長的對象;前者是復制算法,后者是標記清除或標記整理算法;

一共有7個垃圾回收器,注意ParNew和CMS是搭配組合,省略...

8. CMS具體的工作流程?G1與CMS區別?

大致有4個步驟:初始標記->並發標記->重新標記->並發清除,第1和3步會STW(stop the world),這個回收器是以追求響應時間短為目標;

前者有產生浮動垃圾,空間碎片等缺點,后者將堆分為很多個region,不再具有特定的年輕代,老年代,GC時會自適應調整策略,更加智能,也是追求響應時間短為目標。

9. GC Root對象有哪些?

棧中變量引用的對象;方法區中靜態屬性、常量應用的對象;JNI中引用的對象

10. 強引用、軟引用?弱應用?虛引用?

被視為存活對象不會被GC;SoftReference,只有在OOM之前才被GC掉;WeakReference,每次GC時都被GC掉;省略..

11. 類加載機制?tomcat為什么打破雙親委派?

默認有3個類加載器,系統、擴展、應用類加載器,使用雙親委派模型, 即每次優先讓父類加載去加載;tomcat可以同時部署多個應用,安全考慮

建議:注意ClassLoader中loadClass,findClass區別

12. 線程池有哪些?一般怎么用?這些參數的意義是什么?

默認的有4個,fixed, single, cached, scheduled;不過一般用ThreadPoolExecutor, 包含core, max, alive, blockingQueue, threadFactory, abortPolicy,省略...

建議:這個問題是最最最常問的,建議分析下ThreadPoolExecutor源碼,洞察內部實現,就不用死記參數之間的聯系了。

13. 線程池的線程數一般設定多少?

由機器CPU的core數n和並發任務的屬性決定,若任務是CPU密集型,建議設定n+1數量,若任務是IO密集型,建議設定2n數量

14. 線程通信的方式?

volatile, wait/notify/notifyAll, condtion#await/singal等

15. Thread有幾種狀態?

NEW,RUNNING, BLOCKED, WAITING, TIMED_WAITING,TERMINATED

建議:這些狀態定義在Thread類本身;需要注意每個狀態是由哪些方法調用產生的;另外操作系統下的線程本身也有自己的狀態,比JDK定義的更精簡一些,可以自行去對比分析理解

16. sleep與wait區別

前者不會釋放鎖,后者會釋放鎖,兩者都不會占用CPU資源

17. volatile作用?原理?

可見性,有序性(防止重排序);使用內存屏障

建議:內部原理實現比較復雜,涉及CPU lock指令,一致性協議等,可自行深入了解

18. ThreadLocal如何實現?

Thread類本身有ThreadLoalMap屬性,所以每個線程都有獨立的map數據

19.索引類型?

一般回答角度:普通索引,唯一索引,主鍵索引,聯合索引

(有時會問讓從索引結構角度):hash索引,B+樹索引

20. 為什么使用B+樹?而不是用其它二叉樹或B-樹?B+樹與B-樹區別?

前提知識:數據庫是文件存儲系統,瓶頸在IO訪問次數上,樹越高,訪問的次數就越多。

B+樹是多叉樹,相同節點要比二叉樹高度低很多,效率會高很多;

相比B-樹,主要有2點優勢,1. 葉子節點有指針相連,做全表掃描時或范圍查詢時會很快。2. 內部節點不存儲數據,只存儲索引值,相同數據頁存儲的節點信息更多,IO次數也會減少很多,效率就高很多。

21. 聚集索引與非聚集索引區別?

在InnoDB中前者也稱主鍵索引,內部節點存儲主鍵值,葉子節點存儲數據行。后者是內部節點存儲索引值,葉子節點只存儲主鍵值

22. Innodb與Myisam引擎區別?

前者支持事務,后者不支持。前者是聚集索引,后者是非聚集索引

23. 數據庫主從復制過程?binlog日志模式有哪些?

master開啟binlog日志開關,slave節點會有線程去讀取binlog,然后寫回到relay log中,再有線程去讀取relay log,寫到slave節點中;

statement level記錄操作語句, row level記錄操作涉及的所有行數據, mixed level;

24. redolog, undolog區別?

前者是可以恢復被中斷的事務數據,從而繼續提交;后者是可以讓事務回滾到上一個版本。

25. 如果事務未提交,意外宕機?如何恢復?

使用redolog或者undolog恢復。未完成的事務,可以繼續提交,也可以選擇回滾,這基於恢復的策略而定。

26. SQL優化技巧(慢查詢解決方案)

使用explain分析執行計划報告,避免一些索引使用不當的問題,或有沒有必要建立新的索引,另外可以使用緩存,分庫分表解決。

建議:總結出索引使用不當的case,如索引字段參與計算被寫在sql中等

27. 什么是索引覆蓋?

在InnoDB中,select語句中select出來的字段,只包含索引值和主鍵值,不用回表(再次根據主鍵值去查詢主鍵索引,找到數據行)

28. 深層次分頁如何優化?比如 limit 10000, 100這種?

假設主鍵是有序的,先找到100頁的主鍵值a,再根據>a這個條件,再次分頁100,又找到主鍵值b,再根據>b這個條件省略...

建議:這次面試被問到至少3次,前幾年面試真沒遇到過;描述的不精確,可自行去度娘學習

29. spring如何解決循環依賴?

30. springboot相比spring的優勢?

約定大於配置;自啟動一些組件

31. @Conditional作用

當某個bean的初始化依賴某個class時,可以使用此注解

32. redis常用數據結構?

list, string, hash, set, zset

33. 持久化策略?aof與rdb區別?

有aof和rdb;前者是持久化操作指令,且追加寫入,持久化動作快,但恢復慢。后者是持久化當前全量數據,持久化動作慢,但恢復快。

建議:其實還有混合持久化策略,即aof+rdb;aof與rdb的持久化原理也可去深入了解下,有時可能會被問到

35. 過期key的刪除策略?

主動刪除,redis內部有定時去監測key的ttl是否過期;被動刪除,只有在get時會判斷是否過期

36. redis哨兵模式如何保證高可用?

建議:看有沒有用過吧,可以自行研究

37. 對於redis-cluster,如何保證高可用的?數據是如何存儲的?內部節點如何通信?

多master水平分布,每個master背后有slave做備用節點;redis-cluster,默認會有1.6W多個slot,每個key的hash值對slot總量進行取余,定位到某個slot上,slot是分布在某個master上的;

master-master,master-slave,slave-slave都會依賴同一種二進制協議通信,傳達節點信息是否正常,存儲的slot號有哪些,都會告訴其它節點,這樣每個master都知道了slot號與master之間的映射關系。

建議:看有沒有用過吧,可以自行研究

39. 事務隔離級別有哪些?mysql默認是哪個?是如何實現可重復讀的?是如何解決幻讀問題的?

讀未提交,讀已提交,可重復讀,可串行化;默認是可重復讀,RR;MVCC為表新增2個虛擬字段,創建行的版本,刪除行的版本,每次查詢時都是要小於等於創建版本,所以即使其它事務變更該行,也不會影響當前事務的查詢;使用間隙鎖

建議:這些問題特別特別被經常問到。這塊知識涉及當前讀,快照讀,X鎖, S鎖,間隙鎖,undolog等等,建議系統去深入理解總結

40. 分布式鎖怎么實現的?redis鎖怎么防止被誤釋放?怎么防止死鎖?過期時間怎么設置?怎么續約?

對於redis實現,獲取鎖使用setNx命令,設置key,value,expire;可在value中設置UUID,釋放鎖時,通過lua腳本判斷UUID是否一樣,再通過redis的evl命令執行這個腳本;

通過設置過期時間防止死鎖;預估一個過期時間后,可以有一個“看門狗”的線程去檢測鎖的狀態,去自動續約。

建議:這塊需要去系統深入了解下,特別常見。

41. mysql層面樂觀鎖、悲觀鎖實現?

前者加version,在操作sql語句中增加version判斷大小的where條件;select ... for update;

42. 什么是cas,有哪些缺點?

compare and set是原子命令;cpu資源開銷,ABA問題等

43. AQS大致機制?

主要有2個核心的屬性:volatile int state,用於標識鎖的狀態;雙向同步隊列,用於保存等待狀態的線程。另外使用cas去獲取鎖/釋放鎖

建議:去深入源碼了解其機制;注意volatile+cas的使用機制,原子類也是這樣實現的

44. Synchroinzed與ReentrantLock區別?

使用方式角度:前者可修飾屬性、方法、代碼塊,后者只能是代碼塊;

其它角度:前者只能是非公平的,后者可支持公平鎖。前者不能響應等待中斷,后者是能響應等待中斷的。

建議:此問題幾乎必問

45. Synchronized是如何實現的? 鎖優化過程?

每個對象都有一個對象鎖,保存在對象頭中;先由偏向鎖,再升級為輕量級鎖,最后是重量級鎖

建議:特別容易被問到,建議去深入學習

46. ReentrantLock怎么實現的?

繼承AbstractQueuedSynchronizer類,去實現。即基於AQS。

45. wait使用時注意哪些?

要被while循環包住,放在synchroinzed下

46. 場景題匯總:

1) 延時隊列怎么實現的?

建議:參考DelayQueue實現

2) 如何應對未來可能的突發流量?

可從限流、MQ削峰、動態水平擴容等角度去展開講

建議:方案有很多,要實現准備好一種能落地的方案

3) 線上故障排查的思路是什么?

4) 緩存穿透如何解決,緩存雪崩如何解決?

建議:會有布隆過濾器做防緩存穿透的方案;其它可自行去了解學習

5) 你覺得項目的挑戰點/難點/亮點是什么?

建議:要實現准備好,列出個1,2,3,4條出來

6). 動態展示積分排行?zset結構如何實現的?

使用redis的zset結構;跳躍表?

建議:需了解zset大致實現,很容易被追問

7). GC調優經驗?GC線上問題排查?(如內存泄漏)

暫無;jmap出快照,下載到本地后,用mat去分析

建議:根據自己經驗+度娘;

8) 如何排查CPU過高問題?

找到進程pid,top -H -p pid(得出占用CPU資源高到低的線程信息),printf %x id(拿到線程號去轉16進制),再從jstack出的線程棧中去找這個線程號,最后定位到代碼

9). A線程依賴B,B依賴C,怎么實現?

使用wait/notify/notifyAll

10). 待補充...

47. 算法題匯總:

1)  兩個升序數組的差集;輸入2個數組,返回一個數組 

2) 判斷一棵樹是否是平衡二叉樹;輸入root節點,輸出true/false

3) 已知一個升序的數組,給特定值a,求在數組中小於a的最大值(需最優復雜度);輸入數組和a,輸出數組中的某個數

4) 給定2個有序的單鏈表,合並成一個有序的單鏈表,且去除重復元素;輸入2個頭結點,輸出新鏈表的頭結點

5) 將數字123422,翻譯成“拾貳萬叄仟肆佰貳拾貳”,即給定任意數字翻譯成漢字;輸入long型數字,輸出字符串

6) 說下實現LRU的思路,手寫LRU

建議:優先使用HashMap結構與鏈表結合的方案,參考LinkedHashMap

7) 用兩個棧數據結構實現一個隊列的功能,隊列具備入隊、出隊操作功能即可

8) 實現下二分查找

9) 求最大連續子數組之和

10) 實現下插入排序,並說其是否穩定,時間復雜度是什么

11) 實現一個棧(可用JDK中的Stack),要求能額外實現getMin()方法,標識能獲取到此棧的最小值

12) 實現層序遍歷

13)待補充...

48 待補充...

 三、面試技巧:

 上面列出的面試遇到的知識點基本都是大路貨,隨處可見,我們能做的就是盡量去融會貫通,盡量與項目開發實踐中相結合,有自己的心得總結。

對於前3年的,可能對基礎知識考察會多一些;

 對於5年左右甚至更多,可能對項目經驗考察更多一些。

在做面試准備時,要根據自身的情況,有側重點的去准備。

具體一些的話,比如簡歷怎么寫,怎么介紹項目,怎么有針對的准備某塊知識等等技巧,后續有空了補上吧。

四、自我總結:

自己這次面試,是臨時抱佛腳,“應試”的心態去准備面試,這樣肯定是很不好的。

希望以后自己能踏踏實實的,平常多總結,做一個real coder.

 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM