首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Java 多線程面試題精選 50 道:從基礎概念到並發核心原理的系統級復盤指南

     編輯:Java 綜合教學

前言

多線程是 Java 面試必考陣地,覆蓋基礎 API、內存模型、鎖機制、併發工具、線程池、經典模式、故障診斷等全維度。本文精選 50 道高頻題,按知識體系分類,提供核心考點解析、標準回答模板、源碼級深度延伸與避坑提示,助你構建完整知識圖譜,從容應對初中高級崗位面試。

一、線程基礎與創建 (1-8)

1. 什麼是線程?進程與線程區別?

標準答: 線程是 CPU 調度基本單位,進程是資源分配基本單位。一進程含多線程,共享堆/方法區,私有棧/程序計數器。線程切換開銷小於進程。

深度點: Linux 下線程實現為輕量級進程 (LWP),共享 task_struct 部分字段;Java 線程 1:1 映射內核線程。

2. 創建線程的四種方式?

  • 繼承 Thread 重寫 run()
  • 實現 Runnable + new Thread(runnable)
  • 實現 Callable + FutureTask (有返回值、可拋異常)
  • 線程池 ExecutorService.submit() (生產首選)

選型: 優先線程池 → Runnable (無返回) / Callable (有返回)。

3. start() vs run() 區別?

start() 啟動新線程,JVM 調用 run();直接調用 run() 為主線程同步執行,無新線程。

4. Runnable vs Callable?

RunnableCallable
返回值無泛型 V
異常不拋檢查異常可拋異常
配合Thread/ExecutorFutureTask/ExecutorService.submit

5. 線程常見狀態及流轉?

NEW → RUNNABLE (就緒/運行) → BLOCKED (同步鎖) / WAITING (wait/join) / TIMED_WAITING (sleep/waitN) → TERMINATED。注意: Java 無 Running 狀態,RUNNABLE 含就緒與運行。

6. sleep() vs wait() 區別?

sleepwait
所屬類ThreadObject
釋放鎖否是
喚醒方式時間到notify/notifyAll/interrupt
調用前提無必須持有對象鎖 (同步塊)

7. yield() 作用?

提示調度器當前線程願意讓出 CPU,同優先級線程可能獲取執行權。**不保證** 讓出成功,不釋放鎖。

8. 守護線程是什麼?

為用戶線程服務 (GC、JIT 編譯、Netty Reactor)。JVM 只有守護線程時退出。setDaemon(true) 必須在 start() 前調用。

二、同步與鎖機制 (9-18)

9. synchronized 實現原理?

基於 Monitor 對象,編譯為 monitorenter/monitorexit 字節碼。對象頭 Mark Word 存儲鎖狀態、線程 ID、遞歸計數。JDK 6+ 引入偏向鎖→輕量級鎖(自旋+CAS)→重量級鎖(OS Mutex)膨脹機制。

10. volatile 關鍵字語義?

① 可見性:寫入後立即刷新主存,讀取前失效緩存重讀主存。② 禁止指令重排 (內存屏障)。**不保證原子性** (如 i++ 仍非原子)。

11. synchronized vs ReentrantLock?

維度synchronizedReentrantLock
鎖釋放自動 (塊結束/異常)手動 unlock() (finally)
可中斷否lockInterruptibly()
公平性非公平可選公平/非公平
條件變量wait/notify多 Condition
性能JDK 8+ 優化極佳高併發下略優

12. AQS (AbstractQueuedSynchronizer) 核心思想?

基於 state 狀態 + CLH 隊列 + CAS + LockSupport.park/unpark。獨佔/共享模式。tryAcquire/tryRelease 由子類實現語義。核心方法:acquire/release/acquireShared/releaseShared。

13. 什麼是偏向鎖、輕量級鎖、重量級鎖?

Mark Word 鎖標誌位演進:01 無鎖/偏向 → 00 輕量級 (CAS+自旋) → 10 重量級 (OS 互斥量)。偏向鎖針對無競爭優化,輕量級鎖針對低競爭自旋,重量級鎖阻塞等待。

14. ThreadLocal 原理與內存洩漏?

每個 Thread 持有 ThreadLocalMap,Key 為 WeakReference,Value 為對象。**洩漏源:Key 弱引用 GC 後,Value 強引用鏈未斷 (Thread 存活)**。解決:remove()、靜態 ThreadLocal、線程池使用後清理。

15. CAS (CompareAndSwap) 原理與 ABA 問題?

CPU 指令 cmpxchg,原子比較並交換。ABA:值 A→B→A,CAS 認為未變。解決:AtomicStampedReference (版本戳)、AtomicMarkableReference (布爾標記)。

16. CountDownLatch vs CyclicBarrier vs Semaphore?

CountDownLatchCyclicBarrierSemaphore
核心語義倒計時門閂循環屏障信號量/許可證
可重用否是是
典型場景主線程等待多子線程完成多線程分階段同步資源池控制/限流

17. 死鎖四條件與避免策略?

互斥、請求保持、不剝奪、循環等待。破壞任一即可。策略:① 統一加鎖順序 (有序資源編碼) ② tryLock(timeout) 超時放棄 ③ 避免長事務持有鎖 ④ 鎖分段/細粒度。

18. 活鎖、餓死區別?

活鎖:線程狀態持續變化但無法推進 (如雙向禮讓)。餓死:低優先級線程長期獲取不到資源/CPU。死鎖:線程阻塞不變化。

三、Java 內存模型 (JMM) 與並發工具 (19-28)

19. JMM 核心規則:happens-before 原則?

程序順序、鎖規則、volatile 規則、線程啟動、線程終止、對象終結、傳遞性。保證「寫入對讀取可見」與「有序性」。

20. 指令重排類型與禁止手段?

編譯器重排、CPU 重排 (LoadLoad/StoreStore/LoadStore/StoreLoad)。volatile 插入內存屏障、synchronized 隱含屏障、Unsafe.fullFence()。

21. ConcurrentHashMap (JDK 8/17) 實現原理?

數組 + 鏈表/紅黑樹。CAS + synchronized (節點首部) 細粒度分段鎖。擴容支持多線程協助 (ForwardingNode)。size() 用 LongAdder 統計。computeIfAbsent 原子複合操作。

22. ThreadPoolExecutor 核心參數與執行流程?

見文章 ID 168692 詳細解析。核心:core/max、隊列選型決定模型、Worker 循環 getTask、拒絕策略、動態調整。

23. Future、CompletableFuture、CompletionStage 關係?

Future 阻塞獲取結果。CompletableFuture 實現 Future + CompletionStage,支持鏈式編排 (thenApply/thenCompose/thenCombine/allOf/anyOf)、異常處理 (exceptionally/handle)、自定義執行器。

24. ForkJoinPool 工作竊取算法?

雙端隊列 (Deque),任務拆分遞歸,線程從自己隊列頭取任務,空時隨機竊取其他線程隊列尾任務。適用遞歸可分任務 (排序、搜索、流處理)。

25. BlockingQueue 實現對比?

見 ID 168692 表格。核心:put/take 阻塞,offer/poll(timeout) 超時,remainingCapacity。

26. ReadWriteLock / StampedLock 適用場景?

讀多寫少。ReentrantReadWriteLock 讀鎖共享、寫鎖獨佔、支持降級 (寫→讀) 不支持升級。StampedLock (JDK 8) 樂觀讀 (tryOptimisticRead/validate)、無重入、性能更高。

27. 線程安全集合 vs 同步集合?

同步集合:Collections.synchronizedXxx 全鎖、性能差。並發集合:ConcurrentHashMap/CopyOnWriteArrayList/ConcurrentLinkedQueue 分段鎖/CAS/複製於寫、高並發吞吐強。

28. CopyOnWriteArrayList 缺點?

寫入複製數組 (O(n))、內存佔用雙倍、數據一致性為最終一致性 (讀舊快照)、不適用寫多場景。

四、線程池與異步編程 (29-38)

29. 如何合理配置線程池大小?

CPU 密集:核心數 +1。IO 密集:核心數 * (1 + 平均等待/平均工作)。實測調優:壓測觀察 CPU/GC/隊列/延遲。

30. execute() vs submit()?

execute 無返回、異常拋給 UncaughtExceptionHandler。submit 返回 Future、異常包裝在 Future.get() 拋出。

31. 線程池關閉:shutdown vs shutdownNow?

shutdown 不接受新任務、處理完隊列。shutdownNow 嘗試中斷執行中任務、返回未執行列表。標準關閉模式: shutdown() → awaitTermination(timeout) → shutdownNow()。

32. 如何實現線程池優雅關閉?

1. 停止接受外部請求 (限流/熔斷) 2. shutdown() 3. awaitTermination 等待存量 4. 超時 shutdownNow() 強制 5. 記錄未完成任務入庫補償。

33. CompletableFuture 異常處理最佳實踐?

鏈路中任意節點異常 → 後續 thenApply 跳過 → exceptionally/handle 捕獲恢復 → 後續繼續。**注意:** whenComplete 不改變結果類型,handle 可轉換結果。

34. 異步日誌/監控如何不影響主鏈路?

專用單線程/有界隊列線程池 + DiscardOldestPolicy + 異步 Appender (Log4j2/Logback AsyncAppender)。

35. 如何排查線程池隊列積壓/拒絕?

1. jstack 看線程狀態 (RUNNABLE/BLOCKED/WAITING) 2. 監控指標 (隊列長度、活躍數、完成數、拒絕數) 3. 業務執行耗時分布 (before/afterExecute 統計) 4. 檢查鎖競爭、慢 SQL、下游超時。

36. 什麼是線程上下文切換?如何減少?

CPU 從線程 A 切換到 B:保存 A 恢復 B (寄存器、程序計數器、棧指針)。減少:① 無鎖並發 (CAS/ThreadLocal) ② 縮小同步塊 ③ 協程/虛擬線程 (JDK 21) ④ 合理線程池大小避免過多線程。

37. ThreadPoolExecutor 如何實現定時/周期任務?

用 ScheduledThreadPoolExecutor,內部 DelayedWorkQueue (堆) + ScheduledFutureTask (time/period/sequence)。

38. 虛擬線程 (Virtual Thread, JDK 21) 原理與優勢?

用戶態線程 (Continuation),由平台線程 (Carrier Thread) 載體運行。阻塞時讓出 Carrier (unmount),非阻塞繼續。優勢:百萬級併發、代碼同步寫法、無池化需求、簡化 IO 密集型編程。

五、經典並發模式與故障診斷 (39-50)

39. 生產者-消費者模式實現方式?

① wait/notify (教學) ② BlockingQueue (標準) ③ Semaphore (信號量) ④ PipedInputStream/OutputStream (管道) ⑤ Disruptor (高性能環形隊列)。

40. 讀寫鎖實現緩存一致性?

讀操作加讀鎖,寫操作加寫鎖 (雙重檢查 + 寫鎖更新 + 失效緩存)。StampedLock 樂觀讀更優。

41. 雙重檢查鎖 (DCL) 單例寫法與 volatile 作用?

public class Singleton {
    private static volatile Singleton instance;
    private Singleton() {}
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton(); // volatile 禁止指令重排 (分配內存→初始化→賦值)
                }
            }
        }
        return instance;
    }
}

42. 枚舉單例為何最佳?

JVM 保證類加載線程安全、天然防反射/序列化破壞、代碼最簡潔。

43. 如何檢測死鎖?

jstack PID 含 "Found one Java-level deadlock";JConsole/JVisualVM/JMC 圖形化檢測;代碼中 ThreadMXBean.findDeadlockedThreads()。

44. 線程洩漏如何排查?

1. 監控線程數持續增長 2. jstack 分析線程名/狀態/堆疊 3. 命名線程池定位業務 4. 檢查 ThreadLocal 未清理、線程池未關閉、非守護線程未結束。

45. ThreadLocal 在線程池中使用注意事項?

線程復用導致值殘留。**必須** 在任務結束 finally 中 remove()。或用 TransmittableThreadLocal (阿里開源) 支持父子線程傳遞。

46. 如何實現線程間協作:等待結果、超時、取消?

Future.get(timeout)、CompletableFuture.orTimeout()、Future.cancel(true) (中斷)、CountDownLatch.await(timeout)。

47. 什麼是偽喚醒?如何避免?

無 notify 線程被喚醒 (OS/CPU 機制):**永遠在 while 循環中調用 wait()**,檢查條件滿足才退出。

48. 如何保證多線程下單次初始化?

Class.forName、static final、static{}、CallOnce (Guava)、AtomicReference CAS、ClassValue (JDK 8+)。

49. 線程優先級在 Java 中可靠嗎?

映射 OS 優先級 (1-10),**不保證調度順序**,受 OS 調度器支配。不建議依賴優先級控制業務邏輯。

50. 設計高併發系統的三大核心原則?

  1. 無鎖化: CAS、ThreadLocal、CopyOnWrite、RingBuffer、異步非阻塞。
  2. 分層隔離: 業務線程池隔離、資源池隔離、熔斷降級、限流削峰。
  3. 可觀測性: 統一線程命名、鏈路追蹤、指標監控 (隊列/活躍/耗時/拒絕)、日誌關聯。

附錄:面試加分項清單

  • 能畫出 synchronized 膨脹流程圖、AQS 隊列結構圖、ThreadPoolExecutor 執行流程圖
  • 能手寫生產者消費者 (BlockingQueue 版)、DCL 單例、簡易線程池
  • 熟悉 jstack/jmap/jstat/arthas 線上排查實戰案例
  • 了解 JDK 21 虛擬線程、Structured Concurrency、Scoped Values 最新特性
  • 能說出項目中線程池隔離配置、異步編排方案、死鎖/洩漏排查經歷

結語

多線程面試考察的不僅是 API 記憶,更是併發思維、工程判斷、故障經驗。建議以「原理→源碼→實戰→排查」四維建立知識體系,重點攻克 JMM、AQS、線程池、CAS、鎖優化五座大山。面試時敢於說「不知細節但知查找方向」,勝過生硬背誦。祝你 Offer 滿懷!

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved