整理自 journaldev.com 高質量面試題,經鄭旭東翻譯潤色,覆蓋線程生命週期、同步機制、JUC 核心組件、線程池、死鎖排查等高頻考點。
線程基礎篇
1. 進程 vs 線程
進程 = 資源分配單位(獨立內存空間);線程 = CPU 調度單位(共享進程堆/方法區,私有棧/程序計數器)。線程創建/切換開銷遠小於進程。
2. 創建線程三種方式
- 繼承
Thread 重寫 run()
- 實現
Runnable 傳入 Thread 構造(推薦,解耦任務與執行)
- 實現
Callable + FutureTask(有返回值/拋異常)
3. 生命週期六狀態
NEW → RUNNABLE → RUNNING → BLOCKED/WAITING/TIMED_WAITING → TERMINATED。start() 啟動進入就緒,run() 直接調用不啟動新線程。
4. sleep vs wait
| sleep() | wait() |
| 所屬類 | Thread (static) | Object |
| 釋放鎖 | 否 | 是 |
| 喚醒方式 | 時間到/中斷 | notify/notifyAll/中斷 |
| 調用前提 | 無 | 必須持有對象鎖(同步塊中) |
5. yield() 讓出 CPU,不保證重新調度;join() 等待目標線程終止。
同步與鎖篇
6. synchronized 關鍵字
- 修飾實例方法 → 鎖
this
- 修飾靜態方法 → 鎖
Class 對象
- 同步塊
synchronized(obj) {} → 鎖 obj
- 可重入、悲觀鎖、JDK 6+ 鎖升級(偏向→輕量級→重量級)。
7. volatile 關鍵字
- 保證可見性(寫入立即刷主存,讀取從主存)、有序性(禁止指令重排)。
- 不保證原子性:
volatile int i; i++; 仍非線程安全。
- 適用場景:狀態標誌、雙重檢查鎖單例、長整雙讀。
8. Lock 接口優於 synchronized
- 可中斷獲取鎖
lockInterruptibly()
- 嘗試非阻塞獲取
tryLock()/tryLock(timeout)
- 公平鎖選擇
new ReentrantLock(true)
- 多條件變量
newCondition() 精準通知
- 手動釋放鎖需在
finally 中 unlock()
9. AQS (AbstractQueuedSynchronizer) 核心
狀態 state + FIFO 隊列 + CAS 原子操作,模板方法模式支撐 ReentrantLock、Semaphore、CountDownLatch、ReentrantReadWriteLock 等所有同步器。
JUC 核心組件篇
10. 線程池:Executor 框架
Executors 工廠方法(fixedThreadPool/cachedThreadPool/singleThreadExecutor/scheduledThreadPool)生產慎用(隱患:無界隊列 OOM、線程數失控)。
- 自定義
ThreadPoolExecutor 七大參數:core/max/corePoolSize、keepAliveTime、workQueue、threadFactory、handler。
- 拒絕策略:AbortPolicy(默認拋異常)、CallerRunsPolicy(調用者執行)、DiscardPolicy/DiscardOldestPolicy。
11. 阻塞隊列:生產者-消費者基石
| 隊列 | 特性 | 場景 |
| ArrayBlockingQueue | 有界數組、FIFO | 固定緩衝區 |
| LinkedBlockingQueue | 可選有界鏈表、FIFO | 高吞吐、默認無界 |
| PriorityBlockingQueue | 優先級堆、無界 | 任務優先級調度 |
| DelayQueue | 延遲觸發、無界 | 定時任務、緩存過期 |
| SynchronousQueue | 零容量、直接移交 | 線程直接遞交、cachedThreadPool |
12. Callable + Future + FutureTask
Callable 有返回值 V call(),可拋異常。
Future 異步結果句柄:get() 阻塞取結果、cancel()、isDone()。
FutureTask 實現 RunnableFuture,可作任務提交、可作結果獲取,支持手動觸發 run()。
13. 並發容器
ConcurrentHashMap:JDK 8 CAS + synchronized + 紅黑樹,分段鎖 → Node 級鎖,computeIfAbsent 原子複合操作。
CopyOnWriteArrayList/Set:寫時復制,讀無鎖,適合讀多寫少、遍歷佔比高場景。
- 避免
ConcurrentModificationException(fail-fast 迭代器拋出)。
進階問題篇
14. 死鎖四必要條件 + 排查
- 互斥、持有並等待、不可搶佔、循環等待。
- 排查:
jstack pid 獲取線程轉儲,找 BLOCKED 線程與等待的鎖 ID,定位持有鎖線程。
- 預防:固定鎖獲取順序、
tryLock(timeout) 避免無限等待、減小鎖粒度、避免嵌套鎖。
15. ThreadLocal 原理與內存洩漏
- 每線程獨享變量副本,
ThreadLocalMap 掛載於 Thread 對象,Key 為 WeakReference。
- 洩漏源:ThreadLocal 變為不可達但 Thread 存活(線程池),Entry Key 為 null 但 Value 強引用殘留。→ 用完必調
remove(),靜態常量持有 ThreadLocal。
16. 線程轉儲獲取三板斧
jstack -l pid > dump.txt # JDK 自帶,推薦
kill -3 pid # Linux/Unix 信號,輸出到 stdout
jvisualvm / jconsole / arthas # 圖形/附著工具
並發編程核心心法:**共享可變狀態是萬惡之源**。優先不可變對象、線程封閉、無鎖數據結構、Actor 模型;實在需共享,最小化臨界區、適當鎖粒度、避免嵌套鎖、善用 JUC 成熟組件而非手寫同步。
- 上一篇文章: Java 連續奇數合數演算法:暴力解法與效能分析
- 下一篇文章: Java 類別進階:靜態成員、靜態方法與 final 關鍵字深度解析
Copyright ©
程式碼之家 All Rights Reserved