Java 線程生命週期由六種狀態組成,非線性流轉:
NEW (新建)
│ start()
▼
RUNNABLE (可運行) ◄──────────────────────────────┐
│ │
├─ 獲取 CPU 時間片 ──▶ RUNNING (運行) │
│ │
├─ synchronized/lock 等待 ──▶ BLOCKED (阻塞) │
│ │
├─ Object.wait() ──▶ WAITING (無限等待) │
│ │ │
│ └─ 超時等待 ──▶ TIMED_WAITING (限時等待) │
│ │
└─ run() 結束/異常 ──▶ TERMINATED (終止) ◄──┘
| 狀態 | 觸發條件 | 退出條件 | 備註 |
|---|---|---|---|
| NEW | new Thread() | 調用 start() | 未啟動,不佔用 CPU |
| RUNNABLE | start()、鎖釋放、notify、睡眠結束 | 獲得 CPU 執行、等待鎖、調用 wait/sleep | 包含就緒與運行,JVM 不區分 |
| BLOCKED | 嘗試進入 synchronized 方法/塊,鎖被佔用 | 獲得鎖 | 只針對 synchronized,Lock 導致 WAITING |
| WAITING | Object.wait()、Thread.join()、LockSupport.park() | notify/notifyAll、被 join 線程結束、LockSupport.unpark | 無超時,需外部喚醒 |
| TIMED_WAITING | Thread.sleep()、wait(timeout)、join(timeout)、parkNanos/parkUntil | 超時、被喚醒 | 帶超時參數的等待 |
| TERMINATED | run() 正常返回、拋出未捕獲異常 | 不可逆 | 線程生命週期結束 |
// NEW -> RUNNABLE
Thread t = new Thread(() -> {}); // NEW
t.start(); // RUNNABLE
// RUNNABLE -> BLOCKED
synchronized(lock) { // 獲取鎖
// 持有鎖期間其他線程進入此塊 -> BLOCKED
}
// RUNNABLE -> WAITING
synchronized(lock) {
lock.wait(); // 釋放鎖進入 WAITING
}
// RUNNABLE -> TIMED_WAITING
Thread.sleep(1000); // 進入 TIMED_WAITING
lock.wait(2000); // 進入 TIMED_WAITING
t.join(3000); // 進入 TIMED_WAITING
// WAITING/TIMED_WAITING -> RUNNABLE
lock.notify(); // 喚醒一個 WAITING 線程
lock.notifyAll(); // 喚醒所有
LockSupport.unpark(thread); // 喚醒 park 線程
// RUNNABLE -> TERMINATED
// run() 方法執行完畢或拋出異常
class MyThread extends Thread {
@Override
public void run() {
// 線程執行邏輯
for (int i = 0; i < 5; i++) {
System.out.println(getName() + " - " + i);
}
}
}
// 使用
new MyThread().start();
new MyThread().start();
this.getName() 直接獲取線程名class MyTask implements Runnable {
private int counter = 10; // 共享數據
@Override
public void run() {
while (counter > 0) {
System.out.println(Thread.currentThread().getName() + " 賣票: " + counter--);
}
}
}
// 使用:多線程共享同一任務實例
MyTask task = new MyTask();
new Thread(task, "窗口A").start();
new Thread(task, "窗口B").start();
new Thread(task, "窗口C").start();
Thread.currentThread()class MyCallable implements Callable {
@Override
public Integer call() throws Exception {
Thread.sleep(1000);
return 42; // 返回結果
}
}
// 使用
FutureTask ft = new FutureTask<>(new MyCallable());
new Thread(ft).start();
Integer result = ft.get(); // 阻塞獲取結果
System.out.println("Result: " + result);
| 維度 | Thread 繼承 | Runnable 實現 |
|---|---|---|
| 本質 | 類繼承 | 接口實現 |
| 數據共享 | 困難(每個 Thread 獨立實例) | 天然支持(同一 Runnable 實例) |
| 擴展性 | 受單繼承限制 | 可同時實現多接口、繼承其他類 |
| 線程池提交 | 不可直接提交 | 直接提交 executor.submit(runnable) |
| 推薦場景 | 簡單獨立線程、教學演示 | 生產環境、任務邏輯復用、線程池 |
// 啟動
thread.start(); // 絕不調用 run()!
// 休眠(靜態方法,當前線程)
Thread.sleep(1000); // 拋 InterruptedException
// 讓出 CPU(靜態,非阻塞,僅提示調度器)
Thread.yield();
// 等待其他線程結束
t.join(); // 或 join(5000)
// 中斷(協作式)
thread.interrupt(); // 設置中斷標誌
// 線程內需檢查:Thread.interrupted() 或 isInterrupted()
// 睡眠/等待時拋出 InterruptedException
// 守護線程(JVM 僅剩守護線程則退出)
thread.setDaemon(true); // 必須 start() 前設置
// 線程名
thread.setName("Worker-1");
Thread.currentThread().getName();
// 線程優先級(建議勿依賴)
thread.setPriority(Thread.MAX_PRIORITY);
class TicketWindow extends Thread {
private int tickets = 10;
public void run() {
while (tickets > 0) System.out.println(getName() + " 出票: " + tickets--);
}
}
// 三窗口各賣 10 張,共 30 張
class TicketSeller implements Runnable {
private int tickets = 10;
public void run() {
while (tickets > 0) System.out.println(Thread.currentThread().getName() + " 出票: " + tickets--);
}
}
TicketSeller seller = new TicketSeller();
new Thread(seller, "A").start();
new Thread(seller, "B").start();
new Thread(seller, "C").start();
// 共賣 10 張,體現數據共享
ExecutorService 管理線程生命週期,避免頻繁創建銷毀InterruptedException 後重新設置中斷標誌或退出stop()/suspend()/resume() 已棄用,不安全Order-Processor-1,便於排查Java 線程六大狀態(NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED)構成生命週期狀態機。多線程實現強烈推薦 Runnable/Callable + 線程池,避免 Thread 繼承的單繼承限制與耦合問題。掌握狀態轉換觸發點(start/sleep/wait/join/notify/interrupt)、協作式中斷模式、守護線程語義,是編寫正確並發程序的基石。