Java 執行緒生命週期

了解執行緒的生命週期有助於正確管理執行緒和除錯多執行緒程式。

執行緒狀態

Java 執行緒有以下六種狀態(定義在 Thread.State 列舉):

NEW → RUNNABLE ⇄ BLOCKED/WAITING/TIMED_WAITING → TERMINATED
狀態說明
NEW已建立但尚未啟動
RUNNABLE正在執行或準備執行
BLOCKED等待取得鎖
WAITING無限期等待
TIMED_WAITING有時限的等待
TERMINATED執行完畢

NEW 狀態

建立執行緒但尚未呼叫 start()

Thread thread = new Thread(() -> {
    System.out.println("執行中");
});

System.out.println(thread.getState());  // NEW

RUNNABLE 狀態

執行緒正在執行或等待 CPU 排程:

Thread thread = new Thread(() -> {
    while (true) {
        // 執行中
    }
});

thread.start();
System.out.println(thread.getState());  // RUNNABLE

注意:RUNNABLE 包含 Ready(等待 CPU)和 Running(正在執行)兩個子狀態

BLOCKED 狀態

等待取得同步鎖:

Object lock = new Object();

Thread t1 = new Thread(() -> {
    synchronized (lock) {
        try {
            Thread.sleep(10000);  // 持有鎖 10 秒
        } catch (InterruptedException e) {}
    }
});

Thread t2 = new Thread(() -> {
    synchronized (lock) {  // 等待取得鎖
        System.out.println("取得鎖");
    }
});

t1.start();
Thread.sleep(100);  // 確保 t1 先取得鎖
t2.start();
Thread.sleep(100);

System.out.println(t2.getState());  // BLOCKED

WAITING 狀態

無限期等待,需要其他執行緒喚醒:

Object.wait()

Object lock = new Object();

Thread thread = new Thread(() -> {
    synchronized (lock) {
        try {
            lock.wait();  // 等待被 notify
        } catch (InterruptedException e) {}
    }
});

thread.start();
Thread.sleep(100);
System.out.println(thread.getState());  // WAITING

// 喚醒
synchronized (lock) {
    lock.notify();
}

Thread.join()

Thread t1 = new Thread(() -> {
    try {
        Thread.sleep(5000);
    } catch (InterruptedException e) {}
});

Thread t2 = new Thread(() -> {
    try {
        t1.join();  // 等待 t1 完成
    } catch (InterruptedException e) {}
});

t1.start();
t2.start();
Thread.sleep(100);
System.out.println(t2.getState());  // WAITING

LockSupport.park()

Thread thread = new Thread(() -> {
    LockSupport.park();  // 等待 unpark
});

thread.start();
Thread.sleep(100);
System.out.println(thread.getState());  // WAITING

LockSupport.unpark(thread);  // 喚醒

TIMED_WAITING 狀態

有時限的等待:

Thread.sleep()

Thread thread = new Thread(() -> {
    try {
        Thread.sleep(5000);  // 睡眠 5 秒
    } catch (InterruptedException e) {}
});

thread.start();
Thread.sleep(100);
System.out.println(thread.getState());  // TIMED_WAITING

Object.wait(timeout)

Object lock = new Object();

Thread thread = new Thread(() -> {
    synchronized (lock) {
        try {
            lock.wait(5000);  // 最多等待 5 秒
        } catch (InterruptedException e) {}
    }
});

thread.start();
Thread.sleep(100);
System.out.println(thread.getState());  // TIMED_WAITING

Thread.join(timeout)

Thread t1 = new Thread(() -> {
    try {
        Thread.sleep(10000);
    } catch (InterruptedException e) {}
});

Thread t2 = new Thread(() -> {
    try {
        t1.join(5000);  // 最多等待 5 秒
    } catch (InterruptedException e) {}
});

t1.start();
t2.start();
Thread.sleep(100);
System.out.println(t2.getState());  // TIMED_WAITING

TERMINATED 狀態

執行緒執行完畢:

Thread thread = new Thread(() -> {
    System.out.println("執行完畢");
});

thread.start();
thread.join();  // 等待完成
System.out.println(thread.getState());  // TERMINATED

狀態轉換

                    ┌──────────────────────────────────────┐
                    │                                      │
                    ▼                                      │
 ┌─────┐      ┌──────────┐      ┌────────────────────┐     │
 │ NEW │ ──▶  │ RUNNABLE │ ──▶  │    TERMINATED      │     │
 └─────┘      └──────────┘      └────────────────────┘     │
                    │                                      │
                    │ synchronized                         │
                    ▼                                      │
              ┌─────────┐                                  │
              │ BLOCKED │ ─────────────────────────────────┘
              └─────────┘        取得鎖
                    │
                    │ wait/join/park
                    ▼
              ┌─────────┐
              │ WAITING │ ─────────────────────────────────┐
              └─────────┘        notify/中斷                │
                    │                                      │
                    │ sleep/wait(t)/join(t)                │
                    ▼                                      │
         ┌───────────────────┐                             │
         │   TIMED_WAITING   │ ────────────────────────────┘
         └───────────────────┘     超時/notify/中斷

轉換方式

起始狀態目標狀態方式
NEWRUNNABLEstart()
RUNNABLEBLOCKED等待 synchronized
BLOCKEDRUNNABLE取得鎖
RUNNABLEWAITINGwait(), join(), park()
WAITINGRUNNABLEnotify(), join 完成, unpark()
RUNNABLETIMED_WAITINGsleep(t), wait(t), join(t)
TIMED_WAITINGRUNNABLE超時或被喚醒
RUNNABLETERMINATEDrun() 完成或例外

監控執行緒狀態

取得狀態

Thread thread = Thread.currentThread();
Thread.State state = thread.getState();
System.out.println("目前狀態:" + state);

取得所有執行緒

// 取得所有執行緒
Set<Thread> threads = Thread.getAllStackTraces().keySet();
for (Thread t : threads) {
    System.out.println(t.getName() + ": " + t.getState());
}

使用 JMX

ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();

// 取得執行緒資訊
long[] threadIds = threadMXBean.getAllThreadIds();
ThreadInfo[] threadInfos = threadMXBean.getThreadInfo(threadIds);

for (ThreadInfo info : threadInfos) {
    System.out.println(info.getThreadName() + ": " + info.getThreadState());
}

// 檢測死鎖
long[] deadlockedThreads = threadMXBean.findDeadlockedThreads();
if (deadlockedThreads != null) {
    System.out.println("發現死鎖!");
}

中斷機制

中斷執行緒

Thread thread = new Thread(() -> {
    while (!Thread.currentThread().isInterrupted()) {
        // 執行任務
    }
    System.out.println("收到中斷,結束執行");
});

thread.start();
Thread.sleep(1000);
thread.interrupt();  // 送出中斷

處理 InterruptedException

Thread thread = new Thread(() -> {
    try {
        while (true) {
            Thread.sleep(1000);  // 可中斷
            // 執行任務
        }
    } catch (InterruptedException e) {
        // 處理中斷
        System.out.println("被中斷");
        // 重新設定中斷狀態(如果需要上層處理)
        Thread.currentThread().interrupt();
    }
});

thread.start();
thread.interrupt();

中斷對不同狀態的影響

狀態中斷效果
RUNNABLE設定中斷標誌
BLOCKED設定中斷標誌
WAITING拋出 InterruptedException
TIMED_WAITING拋出 InterruptedException

實際範例

監控執行緒

public class ThreadMonitor {
    public static void printThreadStates() {
        Map<Thread.State, Integer> stateCount = new EnumMap<>(Thread.State.class);

        for (Thread t : Thread.getAllStackTraces().keySet()) {
            stateCount.merge(t.getState(), 1, Integer::sum);
        }

        System.out.println("執行緒狀態統計:");
        stateCount.forEach((state, count) ->
            System.out.println(state + ": " + count));
    }
}

等待執行緒完成

public void waitForThreads(List<Thread> threads, long timeout)
        throws InterruptedException {
    long deadline = System.currentTimeMillis() + timeout;

    for (Thread t : threads) {
        long remaining = deadline - System.currentTimeMillis();
        if (remaining <= 0) {
            throw new TimeoutException("等待超時");
        }
        t.join(remaining);
    }
}

重點整理

狀態進入方式離開方式
NEWnew Thread()start()
RUNNABLEstart()、被喚醒完成、等待
BLOCKEDsynchronized取得鎖
WAITINGwait()、join()notify()、完成
TIMED_WAITINGsleep(t)、wait(t)超時、被喚醒
TERMINATEDrun() 完成-
  • 使用 getState() 取得執行緒狀態
  • 使用 interrupt() 中斷等待中的執行緒
  • WAITING 和 BLOCKED 的區別:WAITING 是主動等待,BLOCKED 是被動等待鎖
  • 正確處理 InterruptedException