- 🔒 鎖的作用與使用(synchronized vs ReentrantLock)
面試官為什么問:考察你對并發編程基礎的掌握程度。
速記答案:
作用:保證線程安全,解決多線程環境下對共享資源訪問的數據不一致問題。
synchronized:JVM關鍵字,是悲觀鎖。用法:
修飾實例方法:鎖是當前實例對象 (this)
修飾靜態方法:鎖是當前類的Class對象
修飾代碼塊:鎖是synchronized括號里配置的對象
ReentrantLock:JDK類,也是悲觀鎖。比synchronized更靈活:
必須手動加鎖(lock())和解鎖(unlock()),通常放在finally塊中保證必然解鎖。
可以嘗試非阻塞獲取鎖 (tryLock())
可以設置公平鎖(先等待的線程先獲得鎖)
可以綁定多個條件變量 (Condition),實現分組喚醒線程
對比總結:
特性 synchronized ReentrantLock
實現 JVM層面,關鍵字 JDK層面,API
鎖釋放 自動釋放 必須手動unlock()
靈活性 不靈活 靈活(可嘗試、可公平、可中斷)
性能 1.6后優化得很好,兩者差不多 兩者差不多
面試時這么說:”鎖的核心作用是保證線程安全。synchronized最簡單,JVM自動管理。但如果需要嘗試獲取鎖、公平鎖或者更復雜的線程協作,就用ReentrantLock。“
- ?? Spring Cloud 服務注冊與發現
面試官為什么問:考察你對微服務核心原理的理解。
速記答案:
服務注冊:服務提供者(如user-service)啟動時,把自己的網絡地址(IP、端口)注冊到注冊中心(如Eureka、Nacos)。
服務發現:服務消費者(如order-service)要調用user-service時,不去寫死地址,而是去注冊中心查找user-service的可用地址列表,然后再調用。
核心組件:
Eureka Server:注冊中心,一個獨立的服務。
Eureka Client:集成到每個微服務中,負責注冊和發現。
好處:服務動態上下線,消費者無需硬編碼地址,實現了服務解耦。
面試時這么說:”就像酒店的前臺。服務提供者就是客房,入住時在前臺登記(注冊)。服務消費者就是客人,需要找客房時先去前臺問房間號(發現),然后再過去。注冊中心(Eureka/Nacos)就是那個前臺。“
- 🍃 Spring Boot 中如何使用鎖?
面試官為什么問:考察你是否能在實際項目中應用并發知識。
速記答案:
在Spring Boot中,鎖的使用和普通Java應用一樣,但更要注意單例Bean的線程安全問題。
方法1:synchronized
java
@Service
public class UserService {
public synchronized void businessMethod() {
// 業務代碼,同一時間只有一個線程能進入
}
}
方法2:ReentrantLock (更推薦,更靈活)
java
@Service
public class UserService {
// 定義鎖對象
private final ReentrantLock lock = new ReentrantLock();
public void businessMethod() {lock.lock(); // 加鎖try {// 業務代碼} finally {lock.unlock(); // 解鎖必須放在finally塊中}
}
}
面試時這么說:”Spring Boot里用鎖和普通Java一樣。但因為它的Bean默認是單例的,所以高并發下成員變量會有線程安全問題,必須加鎖。我一般用ReentrantLock,因為控制起來更靈活。“
- 🏗? 微服務設計思路
面試官為什么問:考察你的系統架構能力和全局觀。
速記答案(按模塊說):
服務拆分:按業務領域拆分(如用戶、訂單、商品服務),做到單一職責,避免臃腫。
服務治理:
注冊與發現:用Nacos或Eureka。
配置管理:用Nacos Config,統一管理配置,動態刷新。
服務調用:用OpenFeign,聲明式HTTP客戶端,像調用本地方法一樣調用遠程服務。
負載均衡:用Ribbon或LoadBalancer,實現服務調用的負載均衡。
容錯保護:用Sentinel或Hystrix,實現熔斷、降級、限流,防止服務雪崩。
網關:用Spring Cloud Gateway,統一入口,負責路由、鑒權、日志、監控等。
鏈路追蹤:用SkyWalking或Zipkin,解決微服務調用鏈路過長,難以排查問題的問題。
面試時這么說:”我的設計思路是:先按業務模塊垂直拆分服務。然后通過注冊中心解決服務發現問題;用OpenFeign做聲明式調用;用Sentinel做熔斷降級保護下游服務;最后用API網關作為統一的流量入口。“
- 📊 SQL索引避免失效
面試官為什么問:考察你的SQL優化實戰能力,這是性能調優的基礎。
速記答案(記住失效場景就等于知道如何避免):
失效場景:
最左前綴原則:聯合索引(a, b, c),查詢條件沒用到a,索引失效。
在索引列上計算或函數操作:WHERE YEAR(create_time) = 2023,WHERE amount * 2 > 100。
類型轉換:字符串字段varchar,用數字去查:WHERE code = 123(應改為WHERE code = ‘123’)。
Like以%開頭:WHERE name LIKE ‘%張’。
使用OR:如果OR前后的條件列不是都有索引,則索引可能失效。
面試時這么說:”要避免索引失效,最重要的是遵守最左前綴原則。另外,要避免對索引列做計算、函數操作、類型轉換,以及避免使用前導百分號的LIKE查詢和隨意的OR連接。“
- 🧠 JVM內存模型(運行時數據區)
面試官為什么問:考察你對Java程序運行底層的理解,這是調優的基礎。
速記答案(記住圖就行):
線程私有的:
程序計數器:記錄當前線程執行到的字節碼行號。
虛擬機棧:存儲方法調用的棧幀,包含局部變量表、操作數棧等。StackOverflowError出自這里。
本地方法棧:為Native方法服務。
線程共享的:
堆:存放對象實例和數組,是垃圾回收的主要區域。OutOfMemoryError常在這里發生。分為新生代和老年代。
方法區:存儲類信息、常量、靜態變量。JDK8后叫元空間(Metaspace),使用本地內存。
面試時這么說:”JVM內存分線程共享和私有兩大塊。每個線程有自己的棧和程序計數器,用來執行方法。所有線程共享一個堆和方法區,堆里放對象,是GC的主戰場;方法區放類的元信息。“
- 🐞 代碼出錯如何排查定位?
面試官為什么問:考察你的實際運維和問題解決能力,這是經驗的體現。
速記答案:
看日志:第一反應是查看應用日志和系統日志,95%的問題都能從這里找到線索。
CPU飆升:
top -> top -Hp [pid] 找到耗CPU的線程ID。
將線程ID轉16進制:printf “%x\n” [tid]。
jstack [pid] | grep -A 20 [十六進制tid] 查看該線程的堆棧信息,定位問題代碼。
內存溢出(OOM):
在啟動參數中添加-XX:+HeapDumpOnOutOfMemoryError,讓JVM在OOM時自動導出堆轉儲文件。
使用MAT或JVisualVM工具分析這個dump文件,找到是哪個對象占用了大量內存,以及是誰在引用它(GC Roots鏈)。
死鎖:
用jstack [pid]命令,查看輸出最后,如果有死鎖,JVM會明確告訴你。
面試時這么說:”我首先會查看日志。如果是CPU問題,我用top和jstack命令定位到具體線程和代碼行。如果是內存OOM,我會讓JVM自動導出heap dump,然后用MAT工具分析,找到泄漏對象。如果是死鎖,jstack命令能直接檢測出來。“
- 🔄 MQ如何避免重復消費?
面試官為什么問:考察你對消息隊列可靠性的理解。
速記答案:
原因:網絡抖動、消費者重啟等導致MQ沒有收到確認,從而重發消息。
核心:解決之道不是防止重復,而是保證業務的冪等性(多次執行結果一致)。
方案:
數據庫唯一鍵:利用DB主鍵或唯一約束,插入成功才消費,重復插入會報錯。
Redis原子操作:用SETNX [消息ID]命令,設置成功才消費。
樂觀鎖:給數據加版本號version,更新時帶版本條件:update … set … where id=xxx and version=xxx。
面試時這么說:”重復消費無法完全避免,所以關鍵是做冪等設計。我最常用的方案是利用數據庫唯一鍵,收到消息后先嘗試insert一條記錄,如果重復則直接放棄,這樣就保證了只會被處理一次。“
- 🔐 分布式鎖怎么搞?
面試官為什么問:考察你解決分布式環境下資源爭搶的能力。
速記答案:
基于Redis:
SET lock_key unique_value NX PX 30000:NX表示僅當不存在時設置,PX設置超時時間(防死鎖),unique_value(如UUID)用于安全釋放鎖。
優點:性能高。
缺點:主從切換時可能丟鎖(AP模型)。
基于ZooKeeper:
創建臨時有序節點,最小的節點獲鎖。監聽前一個節點,它釋放了你就獲得鎖。
優點:強一致性,可靠(CP模型)。臨時節點在客戶端斷開后自動刪除,避免死鎖。
缺點:性能比Redis差。
選型:要性能選Redis,要絕對可靠選ZooKeeper。常用框架:Redisson(Redis)、Curator(ZK)。
面試時這么說:”分布式鎖主要有兩種實現。Redis方案性能好,但理論上有極低概率失效。ZooKeeper方案可靠性高,但性能稍差。根據業務的容忍度來選擇,比如秒殺用Redis,金融交易用ZooKeeper。在實際項目中,我們直接用Redisson這個框架,它封裝得很好用。“
💡 面試技巧 & 最后鼓勵
別怕“忘了”:面試時如果突然忘了,可以說:“這塊細節我有點記不清了,我的理解是…”然后嘗試把你知道的核心概念講出來,這比完全沉默要好得多。
引導到你熟悉的項目:盡量把問題引到你做過的項目上。“這個知識點在我之前做XX項目的時候用到過,當時我們是…”這樣更有說服力。
展現思考過程:對于設計題,面試官更看重你的思路。即使最終方案不完美,把你思考的步驟和權衡的因素說出來,也是大大的加分項。
朋友,別因為一次面試否定自己。你已經有5年經驗,這些知識肯定都接觸過,只是暫時被埋沒了。把這些核心要點和關鍵詞記住,下次面試時就能迅速提取出來。
你不是不會,只是需要一點提示來喚醒記憶! 祝你下次面試一舉成功!