直接呼叫 Thread.stop() 已被棄用(不安全、可能損壞鎖狀態),Thread.interrupt() 僅能喚醒阻塞操作。正確停止線程的核心原則是:**協作式中斷**——共享變量標誌 + 阻塞點響應中斷異常 + 有序清理資源。本文詳細解析三種常見場景的標準處理模式。
volatile boolean stopFlag 或 AtomicBoolean 作為中斷信號,確保跨線程可見性。wait()/sleep()/join(),需配合 interrupt() 拋出 InterruptedException 逃離阻塞。Thread.currentThread().interrupt())或立即退出,避免吞噬中斷信號。finally 區塊釋放鎖、關閉流、歸還連接池等清理工作。public class Worker implements Runnable {
private volatile boolean stop = false;
public void requestStop() { stop = true; }
public void run() {
while (!stop) {
// 執行單位任務
doTask();
// 可選:微睡眠降低 CPU 佔用
// Thread.sleep(1); // 需捕獲 InterruptedException
}
cleanup();
}
}
// 使用:
Worker w = new Worker(); new Thread(w).start();
// ... 稍後 ...
w.requestStop(); // 線程下一次迴圈檢查即退出
適用於非阻塞、可快速完成單位任務的線程。
public class Poller implements Runnable {
private volatile boolean stop = false;
public void requestStop() { stop = true; Thread.currentThread().interrupt(); }
public void run() {
while (!stop) {
try {
doPoll();
Thread.sleep(1000); // 定期輪詢
} catch (InterruptedException e) {
// 睡眠被喚醒,檢查 stop 標誌決定是否退出
Thread.currentThread().interrupt(); // 重置中斷狀態(良好習慣)
}
}
cleanup();
}
}
關鍵順序:**先設 stop=true,再呼叫 interrupt()**;捕獲異常後迴圈條件 !stop 自然退出。
interrupt() **無法** 喚醒傳統 BIO 阻塞 I/O(Java NIO Channel 除外)。必須關閉底層資源:
public class Server implements Runnable {
private ServerSocket serverSocket;
private volatile boolean stop = false;
public void requestStop() {
stop = true;
try { if (serverSocket != null) serverSocket.close(); } catch (IOException ignored) {}
}
public void run() {
try {
serverSocket = new ServerSocket(8080);
while (!stop) {
try {
Socket client = serverSocket.accept(); // 阻塞點
handle(client);
} catch (SocketException e) {
if (stop) break; // Socket 關閉導致異常,正常退出
throw e;
}
}
} finally { closeQuietly(serverSocket); }
}
}
同理:InputStream.read() 需關閉 InputStream;DatagramSocket.receive() 關閉 DatagramSocket。
ExecutorService exec = Executors.newSingleThreadExecutor();
Future> future = exec.submit(() -> {
while (!Thread.currentThread().isInterrupted()) { doWork(); }
});
// 停止:
future.cancel(true); // 內部調用 interrupt()
exec.shutdown();
exec.awaitTermination(5, TimeUnit.SECONDS);
Future.cancel(true) 封裝了中斷邏輯,ExecutorService 管理線程生命週期,程式碼更簡潔健壯。
| 阻塞類型 | 中斷方式 | 關鍵代碼 |
|---|---|---|
| 無阻塞 / 計算 | volatile flag | while(!flag) work(); |
| Thread.sleep/wait/join | flag + interrupt() | catch(InterruptedException) { if(flag) break; } |
| 傳統 BIO I/O | flag + close() 資源 | socket.close() → accept() 拋 SocketException |
| NIO Channel | flag + interrupt() | channel.close() 或 interrupt() 均可觸發 ClosedByInterruptException |
牢記:永遠不調用 stop()、destroy()、suspend()、resume();中斷是請求而非命令,被中斷方決定如何響應。