多線程是 Java 並發編程的基石。本文系統講解線程與進程區別、三種創建方式、生命周期狀態轉換、優先級與守護線程,為進階並發學習打牢基礎。
| 維度 | 進程 | 線程 |
|---|---|---|
| 定義 | 程序執行的實例,資源分配單位 | CPU 調度單位,輕量級進程 |
| 內存空間 | 獨立地址空間 | 共享進程堆/方法區,私有棧/程序計數器 |
| 創建開銷 | 大(需分配獨立資源) | 小(共享資源) |
| 切換開銷 | 大(上下文切換重) | 小 |
| 通信方式 | IPC(管道、Socket、共享內存) | 共享內存、volatile、鎖、隊列 |
| 穩定性 | 崩潰不影響其他進程 | 一線程崩潰可導致整進程退出 |
public class MyThread extends Thread {
@Override
public void run() {
System.out.println("Thread running: " + Thread.currentThread().getName());
}
}
// 使用
Thread t = new MyThread();
t.start(); // 必須調用 start(),而非 run()
缺點:Java 單繼承限制,線程邏輯與控制耦合。
public class MyTask implements Runnable {
@Override
public void run() {
System.out.println("Runnable task: " + Thread.currentThread().getName());
}
}
// 使用
Thread t = new Thread(new MyTask());
t.start();
// 或配合線程池
ExecutorService executor = Executors.newFixedThreadPool(10);
executor.submit(new MyTask());
優勢:分離任務邏輯與執行控制,支持線程池復用,可實現多個接口。
public class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
Thread.sleep(1000);
return "Result from " + Thread.currentThread().getName();
}
}
// 使用
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> future = executor.submit(new MyCallable());
try {
String result = future.get(); // 阻塞獲取結果
System.out.println(result);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
} finally {
executor.shutdown();
}
| 特性 | Thread | Runnable | Callable |
|---|---|---|---|
| 返回值 | 無 | 無 | 有 (泛型) |
| 拋出異常 | 無 | 無 | 可拋出 |
| 線程池支持 | 差 | 好 | 好 |
| 適用場景 | 簡單繼承場景 | 通用任務 | 需結果/異常的任務 |
public enum State {
NEW, // 新建:創建未 start()
RUNNABLE, // 可運:含就緒+運行,爭搶 CPU
BLOCKED, // 阻塞:等待監視器鎖
WAITING, // 等待:無超時等待 (wait/join/park)
TIMED_WAITING, // 定時等待:有超時 (sleep/wait/join/parkNanos)
TERMINATED // 終止:run() 結束或異常退出
}
+------------------+
| NEW | (new Thread())
+--------+---------+
|
start()
v
+--------+---------+
| RUNNABLE |<-------------------+
+--------+---------+ |
| |
+----------+----------+ |
| | |
获得 CPU 釋放 CPU/時間片 等待鎖/調用 wait()
| | |
v v v
+-------+ +--------------+ +-------------+
| RUNNING | | TIMED_WAITING | | BLOCKED |
+-------+ +--------------+ +-------------+
| | |
結束/異常| 超時/notify 獲得鎖
| | |
v v v
+--------+---------+
| TERMINATED |
+------------------+
| 方法 | 從狀態 | 到狀態 | 釋放鎖 | 備註 |
|---|---|---|---|---|
| start() | NEW | RUNNABLE | - | 異步啟動 |
| sleep() | RUNNABLE | TIMED_WAITING | 否 | 靜態方法,當前線程 |
| wait() | RUNNABLE | WAITING | 是 | 需在 synchronized 內 |
| wait(timeout) | RUNNABLE | TIMED_WAITING | 是 | |
| join() | RUNNABLE | WAITING | 否 | 等待目標線程結束 |
| lock.lock() | RUNNABLE | BLOCKED | - | 獲取鎖阻塞 |
| notify/notifyAll | WAITING | RUNNABLE | - | 喚醒等待線程 |
| run() 結束 | RUNNABLE | TERMINATED | - | 正常或異常退出 |
已棄用,會導致鎖強制釋放、數據不一致、死鎖風險。
public class GracefulShutdownTask implements Runnable {
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) { // 檢查中斷標誌
try {
doWork();
Thread.sleep(1000); // 可中斷阻塞
} catch (InterruptedException e) {
// 睡眠中被中斷,標誌被清除,需重新設置
Thread.currentThread().interrupt(); // 重新設置標誌
break; // 退出循環
}
}
cleanup(); // 清理資源
}
private void doWork() { /* ... */ }
private void cleanup() { /* ... */ }
}
// 使用
Thread t = new Thread(new GracefulShutdownTask());
t.start();
// ...
t.interrupt(); // 請求中斷
Thread daemon = new Thread(() -> {
while (true) {
System.out.println("Daemon running...");
try { Thread.sleep(1000); } catch (InterruptedException e) { break; }
}
});
daemon.setDaemon(true); // 必須在 start() 前設置
daemon.start();
掌握線程創建方式選擇(優先 Runnable/Callable)、生命周期狀態轉換規則、協作式中斷模式、守護線程特性,是 Java 並發編程的入門必修課。下一步建議深入學習:同步機制(synchronized/Lock)、JUC 工具類、線程池原理、JMM 內存模型。