Thread.sleep()、Object.wait()、BlockingQueue.take()、Lock.lockInterruptibly()。方法簽名加 `throws InterruptedException`,讓調用者決定如何處理。適用於庫代碼、可中斷任務。
public Task takeTask() throws InterruptedException {
return queue.take(); // 直接拋出
}
捕獲後調用 `Thread.currentThread().interrupt()`,保證上層調用棧仍能感知中斷請求。
public void run() {
try {
while (!Thread.currentThread().isInterrupted()) {
Task task = queue.take(); // 可能拋出
task.execute();
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 關鍵:恢復標記
}
}
某些關鍵區不可中斷 (如持久化關鍵狀態),捕獲後記錄標記,完成操作後在 `finally` 中恢復。
public Task getNextTask() {
boolean interrupted = false;
try {
while (true) {
try {
return queue.take();
} catch (InterruptedException e) {
interrupted = true; // 記住被中斷過
}
}
} finally {
if (interrupted) Thread.currentThread().interrupt(); // 最後恢復
}
}
// 錯誤示範
try { queue.take(); } catch (InterruptedException ignored) { }
// 後果:中斷請求丟失、線程池無法正常關閉、應用掛起無法退出
| 方法 | 響應中斷 | 備註 |
|---|---|---|
Thread.sleep/wait/join | ✅ 拋出 IE,清除標記 | |
BlockingQueue.put/take | ✅ 拋出 IE,清除標記 | |
Lock.lockInterruptibly() | ✅ 拋出 IE | 優先用此而非 lock() |
Selector.select() | ✅ 返回 0,不拋出 | 需配合 `wakeup()` |
InputStream.read() | ❌ 不響應 | 關閉 Socket/Channel 可釋放 |
synchronized | ❌ 不可中斷 | 改用 ReentrantLock |
`InterruptedException` 不是錯誤,而是**協作式取消協議**的核心信號。正確處理中斷,是編寫健壯、可優雅關閉的併發程序的基石。記住:「要么拋出,要么恢復標記,絕不吞噬」。