多線程是實現程式並發執行的核心機制,允許單一程式中同時運行多個指令流,每個指令流稱為一個線程,彼此獨立調度。本文將系統剖析 Java 多線程的核心概念、實現方式、狀態模型、同步機制與進階特性。
線程被稱為輕量級進程,擁有獨立執行控制權,由作業系統調度。關鍵差異在於:線程無獨立存儲空間,而是與所屬進程中其他線程共享堆內存與方法區,這使得線程間通訊遠比進程間通訊(IPC)簡單高效。
多線程執行邏輯上「同時」,物理上取決於 CPU 核心數。單核 CPU 透過時間片輪轉實現併發,多核則可真正並行。開發者只需按並發模型設計,無需關心底層調度細節。
與單線程最大區別:多線程代碼執行順序不確定(亂序執行),引發線程調度、數據競態、同步互斥等核心挑戰。
Java 透過 java.lang.Thread 類支援多線程,核心在於指定線程執行代碼(run() 方法)。兩種實現方式:
public class MyThread extends Thread {
private int number;
public MyThread(int num) { this.number = num; }
@Override
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.println("線程 " + number + ": 計數 " + i);
}
}
public static void main(String[] args) {
for (int i = 1; i <= 5; i++) new MyThread(i).start();
}
}
優點:直觀簡單。缺點:Java 單繼承限制,若類已繼承其他父類(如 Applet),無法再繼承 Thread。
public class MyRunnable implements Runnable {
private int number;
public MyRunnable(int num) { this.number = num; }
@Override
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.println("線程 " + number + ": 計數 " + i);
}
}
public static void main(String[] args) {
for (int i = 1; i <= 5; i++)
new Thread(new MyRunnable(i)).start();
}
}
優點:解耦任務與執行機制,支援同一任務多線程並發,利於資源共享與封裝。缺點:需額外創建 Thread 實例,若需不同任務仍需多類實現。
最佳實踐:優先使用 Runnable 或 Callable + 線程池(ExecutorService),配合 Lambda 表達式簡化代碼。
new Thread() 創建,未調用 start()。start() 後,等待 CPU 時間片,包含就緒與運行中。run() 正常返回、拋出未捕獲異常、調用 stop()/destroy()(已棄用,不安全)。優先級範圍 1(MIN)~ 10(MAX),預設 5(NORM)。高優先級線程獲取 CPU 機率較大,但非絕對佔有。透過 getPriority()/setPriority() 存取。注意:優先級不應作為程式正確性依賴,僅作優化提示。
多線程共享堆內存導致訪問衝突。Java 提供 synchronized 關鍵字實現互斥鎖:
public synchronized void accessVal(int newVal) { ... }
實例方法鎖住 this,靜態方法鎖住 Class 對象。同一時刻僅一線程可執行該實例/類的所有同步方法。
synchronized(lockObject) {
// 臨界區代碼
}
可指定任意對象為鎖,靈活控制同步範圍,避免大方法同步導致效率低下(如鎖住 run() 會阻塞同類其他同步方法)。
同步解決「互斥」,阻塞機制解決「協作」(資源就緒通知)。
| 方法 | 所屬類 | 釋放鎖 | 喚醒方式 | 適用場景 |
|---|---|---|---|---|
sleep(ms) | Thread | 否 | 時間到期 | 定時輪詢、延遲執行 |
suspend()/resume() | Thread | 否 | 調用 resume() | 已棄用,易死鎖 |
yield() | Thread | 否 | 調度器重新分配 | 主動讓出 CPU,同優先級輪轉 |
wait()/notify() | Object | 是 | 調用 notify()/notifyAll() | 生產者消費者、條件等待 |
synchronized 方法/塊中調用,否則拋 IllegalMonitorStateException。wait() 釋放鎖並進入等待集;notify() 隨機喚醒一線程,notifyAll() 喚醒所有。此機制類比作業系統 PV 原語,可構建信號量、管程等高級同步構件。
非核心線程,JVM 僅存活非守護線程。當所有用戶線程結束,JVM 退出,守護線程被強制終止(不執行 finally、不釋放鎖)。常用於 GC、JIT 編譯、監控等後台服務。透過 setDaemon(true) 設置,必須在 start() 前調用。
ThreadGroup 樹狀結構管理線程集合,支援批量設置優先級、中斷、守護屬性。亦作為安全邊界,不同組可應用差異化安全策略。現代開發較少直接使用,多由線程池、框架間接管理。
多線程核心在於「多代碼塊併發、亂序執行」。何時使用?
java.util.concurrent 高級組件(鎖、條件、併發集合、Future、CompletableFuture)。掌握多線程非僅是 API 熟悉,更是對併發模型、內存模型(JMM)、鎖優化、無鎖算法的深度理解。