多線程與並發是 Java 面試必考重點,也是高併發系統設計的基石。本文精選 25 道經典面試題,涵蓋線程基礎、同步機制、JUC 包、線程池、死鎖等核心知識點,附帶深度解析,助你構建完整知識體系。
進程:資源分配的基本單位,擁有獨立記憶體空間(堆、棧、方法區),上下文切換開銷大。
線程:CPU 調度的基本單位,隸屬於進程,共享進程堆/方法區,擁有獨立程式計數器、棧幀、本地變數。線程間通信更輕量(共享記憶體)。
用戶線程:JVM 不會因其結束而退出(如 main 線程)。
守護線程:為用戶線程服務(GC、JIT 編譯),所有用戶線程結束 JVM 即退出。
thread.setDaemon(true) 必須在 start() 前調用。
Runnable / Callable 接口,傳入 Thread 構造器(推薦,解耦任務與執行)Thread 類並重寫 run()NEW → RUNNABLE(就緒/運行) → BLOCKED(鎖等待) → WAITING/TIMED_WAITING(無限/限時等待) → TERMINATED。
注意:RUNNABLE 包含就緒與運行,JVM 不區分。
run() 只是普通方法調用,仍在當前線程執行。start() 會請求 JVM 創建新線程,異步執行 run()。
| sleep() | wait() | |
|---|---|---|
| 所屬類 | Thread(靜態) | Object |
| 釋放鎖 | 否 | 是 |
| 喚醒方式 | 時間到自動 | notify/notifyAll/interrupt |
| 調用前提 | 無 | 必須持有對象鎖(同步塊/方法) |
優先級只是提示,不保證 高優先級先執行。受 OS 調度器影響大,Java 不建議依賴優先級控制業務邏輯。
CPU 從一個線程切換到另一個線程,需保存/恢復程式計數器、棧幀、寄存器狀態。頻繁切換會嚴重影響性能(可用 vmstat、pidstat 觀測)。
基於監視器鎖。每個對象有 monitor,monitorenter/monitorexit 字節碼指令實現。JDK 6+ 引入偏向鎖、輕量級鎖、鎖消除、鎖粗化等優化。
同步塊更好:可精確控制鎖範圍,減少鎖持有時間,降低爭用。同步方法鎖住整個對象(或類對象)。
i++ 仍需同步或 AtomicInteger)每個對象天然擁有監視器鎖,線程通信本質是「等待/通知對象的鎖狀態」。若定義在 Thread,則每個線程需綁定特定鎖,靈活性差。
調用 wait() 會釋放鎖並進入等待隊列;notify() 會喚醒等待隊列線程,但需當前線程釋放鎖才能讓被喚醒線程獲取鎖。同步塊保證當前線程持有鎖。
每個線程持有 ThreadLocalMap<ThreadLocal, Object>,Key 為 ThreadLocal 實例(弱引用),Value 為線程局部變數。
應用:資料庫連線、Session 上下文、事務管理、日期格式化 SimpleDateFormat(非線程安全)。
注意:使用後必須 remove(),否則線程池場景會導致記憶體洩漏。
不可分割的操作單元。AtomicInteger、AtomicLong、AtomicReference、AtomicStampedReference(解決 ABA 問題)、LongAdder(高併發計數器,分段累加)。
lockInterruptibly()tryLock()tryLock(timeout, unit)newCondition() 支援多個等待隊列Executor:頂層接口,execute(Runnable)ExecutorService:生命週期管理、提交任務返回 FutureThreadPoolExecutor:核心實現,7 大參數控制Executors:工廠方法(生產禁用,OOM 風險)ScheduledExecutorService:定時/周期任務new ThreadPoolExecutor(
corePoolSize, // 核心線程數
maximumPoolSize, // 最大線程數
keepAliveTime, // 非核心線程存活時間
unit, // 時間單位
workQueue, // 任務隊列(有界/無界)
threadFactory, // 線程工廠(命名、守護屬性)
handler // 拒絕策略
)
四種拒絕策略:AbortPolicy(預設拋異常)、CallerRunsPolicy(調用者執行)、DiscardPolicy(丟棄)、DiscardOldestPolicy(丟棄最舊)。
四條件:互斥、佔有並等待、不可搶佔、循環等待。
排查:jstack pid 生成線程快照,尋找 BLOCKED 狀態線程及其等待的鎖(waiting for <0x...>),定位持有鎖的線程。
tryLock(timeout) 避免無限等待Callable<V> 有返回值、可拋出異常,配合 Future<V> 獲取結果。Runnable 無返回值。
FutureTask 實現 RunnableFuture,既是 Future 又是 Runnable。可包裝 Callable 提交給線程池,也可自定義計算邏輯(如緩存計算結果,避免重複計算)。
ConcurrentHashMap:JDK 8 CAS + synchronized + 紅黑樹,分段鎖升級為節點鎖CopyOnWriteArrayList/Set:讀多寫少場景,寫入時複製底層陣列ConcurrentLinkedQueue:無鎖隊列,CAS 實現BlockingQueue 實現:ArrayBlockingQueue、LinkedBlockingQueue、SynchronousQueue、DelayQueuejstack -l pid > dump.txt(推薦,JDK 自帶)kill -3 pid(Linux/Unix,輸出到標準輸出)多線程並發知識體系龐大,建議按「基礎 → 同步 → JUC → 實戰調優」四階段學習。面試時重點掌握:synchronized/JMM/volatile 原理、線程池參數與拒絕策略、死鎖排查、ConcurrentHashMap 演進、ThreadLocal 記憶體洩漏。實戰中優先使用高層抽象(並發容器、線程池、CompletableFuture),少寫底層同步代碼。