Java 採用協作式中斷:interrupt() 僅設定標記,不強制終止。執行緒必須主動檢查並響應。本文深度解析中斷方法、狀態檢測、異常處理與最佳實務模式。
public void interrupt() {
// 1. 設定中斷狀態為 true
// 2. 若執行緒阻塞於以下方法,拋出 InterruptedException 並清除狀態:
// Object.wait()/wait(long)/wait(long,int)
// Thread.join()/join(long)/join(long,int)
// Thread.sleep(long)/sleep(long,int)
// 3. 若阻塞於 InterruptibleChannel → 關閉通道、ClosedByInterruptException
// 4. 若阻塞於 Selector → wakeup、設定狀態
// 5. 否則僅設定狀態,無其他作用
}
關鍵:中斷是「請求」,非「命令」;阻塞方法主動響應拋異常並清除狀態。
| 方法 | 回傳 | 副作用 | 適用場景 |
|---|---|---|---|
Thread.interrupted() (static) | 當前執行緒中斷狀態 | 清除狀態 | 非阻塞代碼輪詢檢查 |
thread.isInterrupted() (instance) | 指定執行緒中斷狀態 | 不影響狀態 | 監控其他執行緒、不想清除狀態 |
陷阱:連續呼叫兩次 Thread.interrupted() 第二次必回傳 false (首次已清除)。
public void run() {
try {
while (!Thread.interrupted()) { // 非阻塞區檢查
doWork();
Thread.sleep(1000); // 阻塞區自動響應
}
} catch (InterruptedException e) {
// 異常拋出時狀態已清除
Thread.currentThread().interrupt(); // 重設狀態供上層檢查 (關鍵!)
// 清理資源、記錄日誌
} finally {
cleanup();
}
}
public void run() {
while (!Thread.currentThread().isInterrupted()) {
// 大量計算、I/O 等非阻塞操作
if (Thread.interrupted()) { // 檢查並清除
// 可選: 拋出 InterruptedException 統一處理
throw new InterruptedException("中斷請求");
}
processNextBatch();
}
}
// 1. NIO Channel
channel.close(); // 導致阻塞的 read/write 拋出 ClosedByInterruptException
// 2. Selector
selector.wakeup(); // 導致 select() 返回
// 3. Lock.lockInterruptibly()
lock.lockInterruptibly(); // 等待鎖時可被中斷
try {
// critical section
} finally {
lock.unlock();
}
Thread.currentThread().interrupt() 重設狀態或向上拋出finally 區塊確保鎖、連線、檔案釋放Thread.stop() 已棄用,不安全| 錯誤代碼 | 問題 | 修正 |
|---|---|---|
catch (InterruptedException e) {} | 吞噬異常、狀態丟失、上層無感知 | Thread.currentThread().interrupt(); 或 throw new RuntimeException(e) |
while (true) { heavyWork(); } | 無檢查點、無法中斷 | 加入 if (Thread.interrupted()) break; |
thread.stop() | 破壞鎖一致性、資料損毀 | 使用 interrupt() + 協作式檢查 |
忽略 isInterrupted() 於 run() 中 | 中斷請求被忽略 | 迴圈條件檢查 !isInterrupted() |
掌握協作式中斷本質,遵循「檢查→響應→清理」模式,是編寫健壯多執行緒應用的核心技能。