作者介紹
?? 浙江大學軟件工程碩士生
?? 淘天后端研發(fā)工程師
?? 秋招斬獲阿里、字節(jié)、快手、京東、美團等多個大廠研發(fā)ssp/sp
?? 持續(xù)分享秋招經(jīng)驗分享、高頻八股問題、最新大廠面經(jīng)、硬核技術(shù)干貨……
?? 全網(wǎng)同號,歡迎關(guān)注
1、【實習經(jīng)歷】在實習過程中是否遇到過技術(shù)難題?如果有,是如何分析和解決的?
技術(shù)難題
在高并發(fā)場景下,系統(tǒng)接口響應(yīng)時間變長,數(shù)據(jù)庫查詢效率低下。-
分析與解決過程
- 定位問題:通過日志分析和性能監(jiān)控工具(如 Arthas 或 JProfiler)發(fā)現(xiàn)數(shù)據(jù)庫慢查詢是主要瓶頸。
- 數(shù)據(jù)庫優(yōu)化:對慢查詢進行索引優(yōu)化,并引入 Redis 緩存熱點數(shù)據(jù),減少數(shù)據(jù)庫直接訪問。
- 線程池調(diào)優(yōu):調(diào)整線程池的核心線程數(shù)和最大線程數(shù),避免線程過多導致上下文切換開銷過大。
- 異步化處理:使用
CompletableFuture對耗時操作進行異步化處理,提升系統(tǒng)吞吐量。 - 結(jié)果:經(jīng)過優(yōu)化,系統(tǒng)響應(yīng)時間顯著降低,性能得到明顯提升。
2、【并發(fā)編程】請談?wù)剬潭ň€程池的理解,它的使用場景是什么?有哪些優(yōu)缺點?使用線程池時可能存在哪些限制?常見的線程池拒絕策略有哪些?
固定線程池的理解
固定線程池通過Executors.newFixedThreadPool(int nThreads)創(chuàng)建,核心線程數(shù)和最大線程數(shù)相同,且線程數(shù)量固定。使用場景
適用于任務(wù)量穩(wěn)定、執(zhí)行時間較短的任務(wù),例如批量數(shù)據(jù)處理或定時任務(wù)調(diào)度。-
優(yōu)點
- 性能優(yōu)化:線程數(shù)量固定,避免頻繁創(chuàng)建和銷毀線程的開銷。
- 資源控制:能夠有效控制并發(fā)線程數(shù),防止資源耗盡。
-
缺點
- 內(nèi)存風險:如果任務(wù)隊列無界,可能導致內(nèi)存溢出(OOM)。
- 阻塞問題:不適合執(zhí)行耗時較長的任務(wù),容易造成線程阻塞。
限制
動態(tài)擴展不足:線程池大小固定,無法動態(tài)擴展,可能不適合任務(wù)量波動較大的場景。-
常見拒絕策略
- AbortPolicy:直接拋出異常,拒絕新任務(wù)。
- CallerRunsPolicy:由調(diào)用線程執(zhí)行被拒絕的任務(wù)。
- DiscardPolicy:直接丟棄新任務(wù),不拋異常。
- DiscardOldestPolicy:丟棄隊列中最老的任務(wù),嘗試重新提交新任務(wù)。
3、【項目經(jīng)驗】針對黑馬點評項目中的秒殺功能,請詳細描述其實現(xiàn)邏輯。
-
實現(xiàn)邏輯
- 庫存預(yù)熱:將商品庫存加載到 Redis 中,利用 Redis 的原子操作(如
decr)進行庫存扣減。 - 限流與排隊:通過分布式限流工具(如 Redis 的計數(shù)器或令牌桶算法)限制請求流量,避免系統(tǒng)過載。
- 分布式鎖:使用 Redisson 分布式鎖確保同一商品不會被超賣。
- 訂單生成:庫存扣減成功后,將訂單信息寫入消息隊列(如 RabbitMQ),由后臺消費者異步處理訂單入庫。
- 冪等性控制:通過唯一標識(如用戶 ID + 商品 ID)確保用戶不會重復(fù)下單。
- 庫存預(yù)熱:將商品庫存加載到 Redis 中,利用 Redis 的原子操作(如
-
優(yōu)化點
- 緩存熱點數(shù)據(jù):使用 Redis 緩存熱點數(shù)據(jù),減少數(shù)據(jù)庫壓力。
- 異步處理:異步處理訂單生成,提升系統(tǒng)吞吐量。
4、【Redis】Redis 支持哪些數(shù)據(jù)結(jié)構(gòu)?RDB 和 AOF 備份機制的主要區(qū)別是什么?Redis 的過期鍵刪除策略和內(nèi)存淘汰策略分別有哪些?
-
支持的數(shù)據(jù)結(jié)構(gòu)
- 基礎(chǔ)結(jié)構(gòu):String、List、Set、Hash、ZSet(有序集合)。
- 高級結(jié)構(gòu):Bitmap、HyperLogLog、Geo。
-
RDB 和 AOF 的區(qū)別
- RDB:定期生成快照文件,恢復(fù)速度快,但可能丟失最后一次快照后的數(shù)據(jù)。
- AOF:記錄每個寫操作命令,數(shù)據(jù)更完整,但文件體積較大,恢復(fù)速度較慢。
-
過期鍵刪除策略
- 惰性刪除:只有在訪問鍵時檢查是否過期,過期則刪除。
- 定期刪除:定時隨機檢查并刪除過期鍵。
-
內(nèi)存淘汰策略
- noeviction:不淘汰數(shù)據(jù),返回錯誤。
- allkeys-lru:淘汰最近最少使用的鍵。
- volatile-lru:僅淘汰設(shè)置了過期時間的鍵中最近最少使用的鍵。
- allkeys-random:隨機淘汰任意鍵。
- volatile-random:隨機淘汰設(shè)置了過期時間的鍵。
- volatile-ttl:優(yōu)先淘汰剩余生存時間最短的鍵。
5、【Redis】Redisson 分布式鎖的實現(xiàn)原理是什么?其看門狗機制是如何工作的?
分布式鎖實現(xiàn)原理
Redisson 使用 Redis 的SETNX命令實現(xiàn)分布式鎖,確保同一時間只有一個客戶端能夠獲取鎖。-
看門狗機制
- 工作原理:當客戶端成功獲取鎖后,Redisson 會啟動一個后臺線程(看門狗),定期刷新鎖的過期時間,防止因業(yè)務(wù)邏輯執(zhí)行時間過長而導致鎖提前釋放。
- 默認行為:看門狗會每隔 1/3 的鎖過期時間自動續(xù)期。
6、【并發(fā)編程】ThreadLocal 的工作原理是什么?如何避免其引發(fā)的內(nèi)存泄漏問題?在線程池中使用 ThreadLocal 時需要注意哪些事項?
工作原理
每個線程都有一個獨立的ThreadLocalMap,用于存儲線程本地變量。ThreadLocal通過set和get方法操作線程的ThreadLocalMap,確保變量在線程間隔離。-
避免內(nèi)存泄漏
- 清理變量:在使用完
ThreadLocal后,調(diào)用remove方法清除變量。 - 避免強引用:避免將大對象存儲在
ThreadLocal中,減少內(nèi)存占用。
- 清理變量:在使用完
-
線程池注意事項
- 顯式清理:線程池中的線程是復(fù)用的,必須在任務(wù)結(jié)束時顯式調(diào)用
remove方法清理ThreadLocal。 - 數(shù)據(jù)污染:如果未清理,
ThreadLocal變量可能會殘留到下一個任務(wù)中,導致數(shù)據(jù)污染。
- 顯式清理:線程池中的線程是復(fù)用的,必須在任務(wù)結(jié)束時顯式調(diào)用
7、【Java集合】HashMap 是否是線程安全的?請描述其 get 方法的執(zhí)行流程以及底層數(shù)據(jù)結(jié)構(gòu)。在高并發(fā)場景下,HashMap 可能會出現(xiàn)哪些問題?有哪些線程安全的替代方案?它們之間有何區(qū)別?
線程安全性
HashMap是非線程安全的,在多線程環(huán)境下可能出現(xiàn)死循環(huán)或數(shù)據(jù)丟失。-
get 方法流程
- 哈希計算:根據(jù) key 的哈希值計算數(shù)組索引。
- 查找節(jié)點:遍歷鏈表或紅黑樹,找到匹配的 key 并返回對應(yīng)的 value。
底層數(shù)據(jù)結(jié)構(gòu)
JDK 1.8 中,HashMap底層采用數(shù)組 + 鏈表/紅黑樹的結(jié)構(gòu)。-
高并發(fā)問題
- 死循環(huán):多線程同時擴容時可能導致鏈表成環(huán),造成死循環(huán)。
- 數(shù)據(jù)覆蓋:多線程同時寫入可能導致數(shù)據(jù)覆蓋或丟失。
-
線程安全替代方案
- Hashtable:通過
synchronized實現(xiàn)線程安全,性能較差。 - ConcurrentHashMap:基于分段鎖或 CAS 實現(xiàn)高效并發(fā)訪問。
- Collections.synchronizedMap:對
HashMap進行包裝,性能較低。
- Hashtable:通過
-
區(qū)別
- 性能:
ConcurrentHashMap性能最優(yōu),適合高并發(fā)場景。 - 鎖粒度:
Hashtable和synchronizedMap鎖粒度較大,性能較差。
- 性能:
8、【MySQL】MySQL 支持哪些存儲引擎?InnoDB 引擎的索引結(jié)構(gòu)是什么?為什么選擇 B+ 樹作為索引結(jié)構(gòu)?在實際場景中如何合理創(chuàng)建索引?請解釋聯(lián)合索引的作用,并分享實習過程中進行 MySQL 性能優(yōu)化的經(jīng)驗。
-
支持的存儲引擎
- InnoDB:支持事務(wù),適合高并發(fā)場景。
- MyISAM:不支持事務(wù),適合讀多寫少的場景。
- Memory:數(shù)據(jù)存儲在內(nèi)存中,適合臨時數(shù)據(jù)處理。
-
InnoDB 索引結(jié)構(gòu)
- 主鍵索引:B+ 樹,葉子節(jié)點存儲數(shù)據(jù)行。
- 輔助索引:B+ 樹,葉子節(jié)點存儲主鍵值。
-
選擇 B+ 樹的原因
- 查詢效率:B+ 樹的高度較低,查詢效率高。
- 范圍查詢:所有數(shù)據(jù)都在葉子節(jié)點,范圍查詢效率更高。
-
合理創(chuàng)建索引的原則
- 查詢頻率:對查詢頻率高的字段創(chuàng)建索引。
- 更新頻率:避免對更新頻繁的字段創(chuàng)建索引。
- 最左前綴原則:使用聯(lián)合索引時遵循最左前綴原則。
聯(lián)合索引作用
聯(lián)合索引可以加速多條件查詢,減少單字段索引的數(shù)量。-
性能優(yōu)化經(jīng)驗
- 添加索引:添加合適的索引,避免全表掃描。
- 分析 SQL:使用 EXPLAIN 分析 SQL 執(zhí)行計劃。
- 減少字段:避免 SELECT *,只查詢需要的字段。
9、【JVM】JVM 中堆和棧的主要區(qū)別是什么?對象的生命周期是如何管理的?垃圾回收機制的工作原理是什么?對于未被回收的對象,JVM 會如何處理?
-
堆和棧的區(qū)別
- 堆:存放對象實例,所有線程共享,GC 的主要區(qū)域。
- 棧:存放局部變量和方法調(diào)用,線程私有,隨方法調(diào)用和返回自動分配和釋放。
-
對象生命周期
- 創(chuàng)建:通過
new關(guān)鍵字分配內(nèi)存。 - 使用:對象被引用并參與業(yè)務(wù)邏輯。
- 回收:當對象不再被引用時,由 GC 回收。
- 創(chuàng)建:通過
-
垃圾回收機制
- 標記-清除:標記存活對象,清除未標記對象。
- 復(fù)制算法:將存活對象復(fù)制到另一塊內(nèi)存。
- 標記-整理:標記存活對象并整理內(nèi)存。
未被回收的對象
如果對象仍有引用或處于 GC Roots 可達路徑中,JVM 不會回收。
10、【Java基礎(chǔ)】volatile 關(guān)鍵字的作用是什么?其底層實現(xiàn)原理是什么?
-
作用
- 可見性:當一個線程修改了
volatile變量,其他線程可以立即感知。 - 禁止重排序:確保程序執(zhí)行順序符合預(yù)期。
- 可見性:當一個線程修改了
-
底層實現(xiàn)原理
- 內(nèi)存屏障:通過內(nèi)存屏障(Memory Barrier)實現(xiàn):
- 寫操作后插入 Store 屏障,強制刷新到主內(nèi)存。
- 讀操作前插入 Load 屏障,強制從主內(nèi)存加載最新值。
- 內(nèi)存屏障:通過內(nèi)存屏障(Memory Barrier)實現(xiàn):
?? 關(guān)注【碼間煙火錄】,解鎖秋招通關(guān)秘籍! ??
?? 這里有你想要的一切:
? 超全秋招經(jīng)驗分享
? 高頻八股問題解析
? 最新大廠面經(jīng)合集
? 海量技術(shù)干貨
本文由mdnice多平臺發(fā)布