Java八股文面試50問速通:從JVM到Spring Boot全覆蓋

八股文專題作者: 美歷團隊

涵蓋JVM、並發、Spring、MySQL、Redis、消息隊列、分佈式7大模組50道Java高頻面試題,每題含簡要答案方向,助你速通技術面。

Java八股文面試50問速通:從JVM到Spring Boot全覆蓋

背景介紹

說實話,我第一次聽到「八股文」這個詞的時候還挺反感的——什麼年代了還背題?但面了七八家大廠之後我徹底悟了:八股文不是讓你死記硬背,而是幫你建立知識體系的骨架。我整理了這50道最高頻的Java面試題,每一道都是我在真實面試中被問到的,覆蓋JVM、並發、Spring、MySQL、Redis、消息隊列、分佈式七大模組。不管你是校招還是社招,吃透這些,面試至少能過技術面。

一、JVM(8題)

1. JVM內存模型是怎樣的?

堆(新生代+老年代)、方法區/元空間、虛擬機棧、本地方法棧、程序計數器。堆是線程共享的,棧和計數器是線程私有的。面試官最愛追問:為什麼要把堆分新生代和老年代?因為大部分對象朝生夕死,新生代用複製算法效率高。

2. 說一下GC算法有哪些?

標記-清除(有碎片)、標記-整理(無碎片但慢)、複製算法(新生代用,快但費空間)、分代收集(綜合方案)。追問必問CMS和G1:CMS用標記-清除,有浮動垃圾和碎片問題;G1用分區+混合回收,可預測停頓時間。

3. 類加載機制和雙親委派模型?

加載→驗證→準備→解析→初始化。雙親委派:先讓父加載器加載,父加載器搞不定才自己來。好處是避免重複加載和安全問題。打破雙親委派的例子:SPI機制(線程上下文類加載器)、Tomcat(每個webapp獨立類加載器)。

4. 什麼情況下會發生OOM?怎麼排查?

堆溢出(對象太多)、元空間溢出(動態生成類太多)、棧溢出(遞歸太深)。排查:jmap看堆內存、jstack看線程棧、MAT分析dump文件。我面試時被追問過線上OOM怎麼處理——先加-XX:+HeapDumpOnOutOfMemoryError參數,出了問題有dump可分析。

5. JVM調優參數有哪些?

-Xms/-Xmx設堆大小、-Xmn設新生代大小、-XX:SurvivorRatio設Eden和Survivor比例、-XX:MetaspaceSize設元空間大小、-XX:+UseG1GC選垃圾收集器。實際調優經驗:先把-Xms和-Xmx設一樣避免動態擴容,G1的MaxGCPauseMillis設200ms。

6. 強引用、軟引用、弱引用、虛引用的區別?

強引用不回收、軟引用內存不足時回收(適合緩存)、弱引用GC就回收(ThreadLocal的key)、虛引用僅用於跟蹤GC活動。這個題看著簡單,但面試官會追問ThreadLocal內存洩漏——key是弱引用會被回收,但value是強引用不會,所以用完要remove。

7. JVM中對象的創建過程?

類加載檢查→分配內存(指針碰撞或空閒列表)→初始化零值→設置對象頭→執行init方法。並發安全用CAS或TLAB。追問:對象在內存中的佈局?對象頭(Mark Word+類型指針)、實例數據、對齊填充。

8. 垃圾收集器怎麼選擇?

單CPU小內存用Serial、多CPU追求吞吐用Parallel Scavenge+Parallel Old、低延遲用CMS或G1、大堆+可預測延遲用ZGC。實際經驗:JDK8用CMS或G1,JDK11+直接G1,JDK15+可以考慮ZGC。

二、並發(10題)

9. synchronized和ReentrantLock的區別?

synchronized是關鍵字,ReentrantLock是API;synchronized自動釋放鎖,ReentrantLock要手動unlock;ReentrantLock支持公平鎖、可中斷、多條件變量。我面試時被問:什麼場景用ReentrantLock更好?答:需要公平排隊、需要tryLock避免死鎖、需要多個Condition時。

10. volatile關鍵字的作用?

保證可見性(刷回主內存)和禁止指令重排序,不保證原子性。底層用內存屏障實現。經典場景:DCL單例模式中instance要加volatile防止初始化一半的對象被其他線程看到。

11. 線程池的核心參數和執行流程?

corePoolSize、maximumPoolSize、keepAliveTime、workQueue、threadFactory、rejectedExecutionHandler。執行流程:先核心線程→再隊列→再非核心線程→再拒絕策略。四大拒絕策略:AbortPolicy(拋異常)、CallerRunsPolicy(調用者執行)、DiscardPolicy(丟棄)、DiscardOldestPolicy(丟棄最老)。面試必問:線程池怎麼設置參數?CPU密集型設N+1,IO密集型設2N或根據公式計算。

12. AQS原理?

核心是volatile int state和一個CLH雙向等待隊列。獨佔模式(ReentrantLock)state為0可獲取,為1則入隊等待;共享模式(Semaphore)state表示剩餘許可數。模板方法模式:子類實現tryAcquire/tryRelease。我面試時被讓手寫一個簡單的AQS——其實就是繼承AQS重寫tryAcquire就行。

13. ThreadLocal原理和內存洩漏問題?

每個Thread對象有個ThreadLocalMap,key是ThreadLocal弱引用,value是強引用。內存洩漏原因:ThreadLocal被GC後key變null,但value還在。解決方案:用完調用remove()。追問:線程池中用ThreadLocal要注意什麼?線程復用導致數據串,一定要在finally裡remove。

14. CAS是什麼?有什麼問題?

Compare And Swap,比較並交換,樂觀鎖的實現。問題:ABA問題(用AtomicStampedReference解決)、自旋開銷(競爭激烈時CPU空轉)、只能保證一個共享變量的原子操作(用AtomicReference包裝多個變量)。

15. 說說Java中的鎖分類?

悲觀鎖/樂觀鎖、公平鎖/非公平鎖、獨佔鎖/共享鎖、可重入鎖/不可重入鎖、自旋鎖/阻塞鎖。synchronized是悲觀、非公平、獨佔、可重入鎖。ReentrantLock默認非公平,可設公平。

16. CountDownLatch和CyclicBarrier的區別?

CountDownLatch是一次性的,等N個線程完成;CyclicBarrier可復用,N個線程互相等待到齊後繼續。場景:CountDownLatch適合主線程等待子線程完成,CyclicBarrier適合多線程分段計算後彙總。

17. Fork/Join框架?

分治+工作竊取算法。大任務拆成小任務fork出去,結果join合併。工作竊取:空閒線程從別的線程隊列尾部偷任務執行。適合CPU密集型的遞歸計算任務。

18. happen-before原則?

八大規則:程序順序、volatile、鎖、傳遞性、線程啟動、線程終止、線程中斷、對象終結。不是「時間上先發生」,而是「前一個操作的結果對後一個操作可見」。

三、Spring(8題)

19. Spring IOC的理解?

控制反轉,把對象的創建和依賴管理交給容器。實現方式:依賴注入(DI),包括構造器注入、Setter注入、字段注入(@Autowired)。Bean生命週期:實例化→屬性賦值→初始化→使用→銷毀。面試官愛問:BeanPostProcessor和BeanFactoryPostProcessor的區別?前者處理Bean實例,後者處理BeanDefinition。

20. Spring AOP的實現原理?

JDK動態代理(接口)和CGLIB(類)。Spring默認有接口用JDK代理,沒接口用CGLIB。SpringBoot2.x默認全部CGLIB。通知類型:Before、After、AfterReturning、AfterThrowing、Around。我面試時被問:AOP失效場景?內部方法調用(沒走代理)、private方法、static方法。

21. Spring事務傳播機制?

REQUIRED(默認,有則加入無則新建)、REQUIRES_NEW(總是新建,掛起當前)、NESTED(嵌套事務)、SUPPORTS、NOT_SUPPORTED、MANDATORY、NEVER。最常考REQUIRED vs REQUIRES_NEW:前者內外同一事務一起回滾,後者內層獨立回滾不影響外層。

22. Spring如何解決循環依賴?

三級緩存:singletonObjects(完整Bean)、earlySingletonObjects(早期引用)、singletonFactories(Bean工廠)。流程:A創建→發現依賴B→B創建→發現依賴A→從三級緩存拿A的早期引用→B完成→A完成。注意:構造器注入和原型模式無法解決。面試追問:為什麼需要三級緩存而不是兩級?為了處理AOP代理,保證早期引用和最終引用一致。

23. @Autowired和@Resource的區別?

@Autowired按類型注入(Spring),@Resource按名稱注入(JSR-250)。@Autowired配合@Qualifier按名稱,@Resource的name屬性指定名稱。面試官會問:多個同類型Bean怎麼辦?@Primary或@Qualifier。

24. SpringBoot自動裝配原理?

@SpringBootApplication包含@EnableAutoConfiguration→通過SpringFactoriesLoader加載META-INF/spring.factories中的配置類→根據@Conditional條件過濾→裝配Bean。SpringBoot2.7+改用META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports。

25. Spring中設計模式的應用?

工廠(BeanFactory)、單例(Bean默認scope)、代理(AOP)、模板方法(JdbcTemplate)、觀察者(事件機制)、適配器(HandlerAdapter)、策略(ResourceLoader)。這個題能展示你對Spring的理解深度。

26. SpringMVC的請求處理流程?

請求→DispatcherServlet→HandlerMapping找Handler→HandlerAdapter執行→Controller處理→返回ModelAndView→ViewResolver解析視圖→響應。面試追問:攔截器和過濾器的區別?攔截器是Spring的,過濾器是Servlet的;攔截器能拿到Handler信息,過濾器不能。

四、MySQL(8題)

27. MySQL索引的數據結構?為什麼用B+樹?

InnoDB用B+樹。原因:1)樹矮(3-4層存千萬數據),IO少;2)葉子節點鏈表連接,範圍查詢快;3)非葉子只存key,一個頁能存更多key。追問:聚簇索引vs非聚簇索引?聚簇索引葉子存整行數據(主鍵索引),非聚簇索引葉子存主鍵值(二級索引),查非索引列要回表。

28. 事務的隔離級別?

讀未提交(髒讀)、讀已提交(不可重複讀)、可重複讀(幻讀,MySQL默認)、串行化。InnoDB在RR級別通過MVCC+間隙鎖解決大部分幻讀。MVCC:每行有隱藏列trx_id和roll_pointer,讀操作通過ReadView判斷可見性。

29. MySQL鎖機制?

表鎖(開銷小並發低)、行鎖(開銷大並發高)、間隙鎖(鎖索引間隙防幻讀)、臨鍵鎖(行鎖+間隙鎖)。InnoDB行鎖是加在索引上的,不走索引則退化為表鎖!面試必問:怎麼查看鎖情況?show engine innodb status或查information_schema.INNODB_LOCKS。

30. 慢查詢怎麼優化?

1)EXPLAIN看執行計劃;2)檢查是否走索引;3)避免select *;4)避免索引失效(函數、隱式轉換、%開頭like、or);5)合理建索引(聯合索引最左前綴);6)分頁優化(延遲關聯);7)數據量大考慮分庫分表。

31. 聯合索引的最左前綴原則?

索引(a,b,c)能匹配a、a,b、a,b,c,不能匹配b、c、b,c。但MySQL優化器會調整順序,where b=1 and a=2也能用索引。範圍查詢後的列不走索引:where a>1 and b=2,只有a走索引。

32. MySQL主從複製原理?

主庫寫binlog→從庫IO線程拉取binlog寫relay log→從庫SQL線程執行relay log。異步複製可能丟數據,半同步複製至少一個從庫確認收到binlog。追問:主從延遲怎麼處理?讀自己的主庫、強制走主庫、判斷seconds_behind_master。

33. 分庫分表方案?

垂直拆分(按業務拆庫)、水平拆分(按規則分表)。分片鍵選擇:查詢頻率高的字段。中間件:ShardingSphere、MyCat。分庫分表後的問題:分佈式事務、跨庫join、全局ID(雪花算法)、數據遷移。

34. EXPLAIN中type字段的含義?

從好到差:system>const>eq_ref>ref>range>index>ALL。至少要達到range級別,避免ALL(全表掃描)。Extra中Using index表示覆蓋索引(好),Using filesort和Using temporary需要優化。

五、Redis(6題)

35. Redis為什麼快?

1)純內存操作;2)單線程避免上下文切換和鎖競爭;3)IO多路復用(epoll);4)高效的數據結構。追問:Redis6.0為什麼引入多線程?為了提升網絡IO性能,命令執行還是單線程。

36. Redis的數據結構?

5種基本:String、List、Hash、Set、ZSet。底層編碼:String用SDS、List用quicklist、Hash用ziplist/hashtable、Set用intset/hashtable、ZSet用ziplist/skiplist+hashtable。面試官愛問:skiplist為什麼不用紅黑樹?實現簡單、範圍查詢方便、插入只需調整相鄰節點。

37. Redis持久化方式?

RDB(快照,恢復快但可能丟數據)和AOF(追加日誌,數據安全但文件大)。混合持久化:RDB做全量+AOF做增量。AOF三種刷盤策略:always(每條)、everysec(每秒)、no(系統決定)。推薦everysec。

38. Redis緩存穿透、擊穿、雪崩?

穿透(查不存在的數據):布隆過濾器、緩存空值。擊穿(熱點key過期):互斥鎖、熱點key永不過期。雪崩(大量key同時過期):隨機過期時間、多級緩存、限流降級。這三個問題幾乎必考,要能完整說出方案。

39. Redis集群方案?

主從複製(讀寫分離)、哨兵(自動故障轉移)、Cluster(分片存儲16384個slot)。Cluster方案:客戶端key做CRC16%16384算slot,每個節點負責一部分slot。面試追問:集群能保證強一致性嗎?不能,異步複製可能丟數據。

40. Redis分佈式鎖怎麼實現?

SET key value NX EX 30(原子操作)。value用UUID防止誤刪別人的鎖。釋放鎖用Lua腳本保證原子性:先判斷value是否一致再刪除。Redisson框架做了看門狗自動續期。追問:RedLock算法?多個Redis實例,過半加鎖成功才算成功,但有爭議。

六、消息隊列(5題)

41. 為什麼用消息隊列?

解耦、異步、削峰。缺點:系統複雜度增加(重複消費、消息丟失、順序問題)、可用性降低。面試官會問:怎麼保證消息不丟?生產者確認+MQ持久化+消費者手動ACK。

42. Kafka架構和核心概念?

Producer→Broker(Topic→Partition→Replica)→Consumer Group。Partition是並行度單位,同一Consumer Group內一個Partition只能被一個Consumer消費。ISR機制:Leader維護一個同步副本集合,只有ISR中的副本才能成為新Leader。

43. Kafka怎麼保證消息順序?

同一Partition內消息有序。要保證全局有序只能一個Partition(不推薦)。實際方案:相同業務key發到同一Partition。追問:Consumer rebalance導致重複消費怎麼辦?冪等處理。

44. RocketMQ和Kafka的區別?

RocketMQ支持事務消息、延遲消息、消息回溯;Kafka吞吐更高、生態更好。RocketMQ用NameServer(無狀態),Kafka用ZooKeeper。選型:日誌採集用Kafka,業務消息用RocketMQ。

45. 消息積壓怎麼處理?

緊急:增加Consumer數量(注意不能超過Partition數)、臨時擴容Consumer。長期:排查消費慢的原因、優化消費邏輯、增加Partition。我遇到過一次線上積壓500萬條,最後是消費端DB慢查詢導致的。

七、分佈式(5題)

46. CAP定理和BASE理論?

CAP:一致性、可用性、分區容錯性三者不可兼得,網絡分區必然存在,所以CP或AP二選一。BASE:基本可用、軟狀態、最終一致性,是CAP中AP的延伸。ZooKeeper是CP(選舉期間不可用),Eureka是AP(不去強一致)。

47. 分佈式鎖的實現方案?

Redis(SET NX EX)、ZooKeeper(臨時順序節點)、MySQL(唯一索引或for update)。對比:Redis性能高但可靠性一般、ZK可靠但性能低、MySQL最簡單但不適合高並發。實際推薦Redis+Redisson。

48. 分佈式事務方案?

2PC(強一致但阻塞)、TCC(Try-Confirm-Cancel,業務侵入大)、SAGA(長事務拆分+補償)、本地消息表+MQ(最終一致)、Seata框架。面試常問:你們項目用的什麼方案?大多數互聯網項目用最終一致性就夠了。

49. 分佈式ID生成方案?

UUID(無序太長)、數據庫自增(性能瓶頸)、號段模式(一次取一批)、雪花算法(時間戳+機器ID+序列號,趨勢遞增)、Redis自增。雪花算法問題:時鐘回撥(保留幾位做回撥檢測)。

50. 服務熔斷和降級的區別?

熔斷是調用方保護自己(連續失敗後直接斷開,類似保險絲),降級是主動放棄非核心功能保核心(返回默認值或兜底數據)。Sentinel和Hystrix都支持。熔斷三狀態:關閉→打開→半打開(試探恢復)。

真題彙總

以上50題就是我在字節、阿里、美團、快手等大廠面試中真實遇到的高頻題。其中最常被問到的Top 10:JVM內存模型、GC算法、synchronized和ReentrantLock、線程池參數、AQS、Spring循環依賴、MySQL索引、事務隔離級別、Redis緩存三連、分佈式鎖。建議按出現頻率從高到低準備。

心得建議

1. 不要死記硬背,理解原理才能應對追問。面試官一個「為什麼」就能篩掉背答案的人。

2. 建立知識圖譜,比如JVM→GC→調優是一條線,synchronized→鎖升級→AQS是一條線,串聯起來記憶更牢固。

3. 結合項目經驗,每個知識點準備一個實際場景。比如「我在項目中遇到OOM,通過jmap發現是ThreadLocal沒remove導致的內存洩漏」。

4. 適度刷源碼,不用全看,但AQS的acquire/release、Spring的getBean流程、HashMap的put流程建議跟一遍。

5. 模擬面試,找人互相問,能說出來和能寫出來是兩回事,能流暢表達又是另一回事。

FAQ

Q:八股文要背到什麼程度?

A:至少能用自己的話完整說出來,關鍵術語不能錯,能應對一層追問。比如你說完JVM內存模型,面試官問「方法區和元空間的區別」,你得接得住。

Q:只準備八股文夠嗎?

A:不夠。八股文是基礎,還需要項目經驗、算法、系統設計。但八股文不過關,其他再好也過不了技術面。

Q:社招和校招八股文側重點一樣嗎?

A:校招偏基礎原理(JVM、並發、集合),社招偏實戰經驗(調優、排障、架構選型)。社招一定要結合項目講,不能純背。

Q:多久能準備完這50題?

A:有Java基礎的,集中準備2-3週。建議每天5-8題,每題理解+寫筆記+能口述。不要貪多,吃透比刷量重要。

#Java#八股文#JVM#Spring#MySQL#Redis#並發#分布式#面試題