Thread.stop()、suspend()、resume() 自 JDK 1.2 起被棄用,因其強制釋放鎖導致數據不一致。本文詳解標準的「標誌位 + 中斷」優雅終止模式,並分析 volatile 關鍵字對可見性的保證。
finally 清理資源(關閉連接、釋放文件句柄)public class GracefulShutdownThread extends Thread {
// volatile 保證:主線程修改對工作線程立即可見,禁止指令重排
private volatile boolean running = true;
@Override
public void run() {
while (running) {
try {
// 模擬業務邏輯
doWork();
// 可中斷阻塞,響應 interrupt()
Thread.sleep(5000);
} catch (InterruptedException e) {
// 關鍵:睡眠被中斷,異常中清除中斷狀態
// 此處應退出循環,而非繼續
Thread.currentThread().interrupt(); // 可選:恢復中斷狀態供上層感知
break; // 或 return 直接結束 run()
}
}
// 清理資源
cleanup();
}
// 對外提供的安全停止入口
public void shutdown() {
running = false; // 1. 設置標誌位(非阻塞場景生效)
interrupt(); // 2. 中斷阻塞(睡眠/IO/鎖等待)
}
private void doWork() { /* 業務邏輯 */ }
private void cleanup() { /* 關閉連接、釋放鎖等 */ }
}
running = false,工作線程下次讀取必見新值running = false 重排到其他操作之後無 volatile 時,JIT 可能將循環優化為 if (running) while(true) ... 導致永不退出。
sleep()、wait()、join()、Channel 操作等阻塞方法會拋出 InterruptedExceptioncatch (InterruptedException e) {
// 方案 A:直接退出(最常見)
break;
// 方案 B:恢復標誌,讓上層調用者感知(若 run() 不直接結束)
Thread.currentThread().interrupt();
}
while (running && !currentThread().isInterrupted()) {
// 計算密集型任務,無阻塞調用
heavyCompute();
// 定期主動檢查中斷標誌
if (currentThread().isInterrupted()) break;
}
public static void main(String[] args) throws InterruptedException {
GracefulShutdownThread worker = new GracefulShutdownThread();
worker.start();
// 主線程做其他事...
Thread.sleep(10000);
// 發起優雅關閉
worker.shutdown();
// 等待線程真正結束(可設超時)
worker.join(5000);
if (worker.isAlive()) {
System.err.println("警告:線程未在5秒內結束,可能卡死");
} else {
System.out.println("線程已優雅退出");
}
}
ExecutorService executor = Executors.newFixedThreadPool(10);
// 提交任務...
executor.shutdown(); // 拒絕新任務,等待現有任務完成
try {
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
executor.shutdownNow(); // 強制中斷執行中任務
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
System.err.println("線程池未能正常關閉");
}
}
} catch (InterruptedException e) {
executor.shutdownNow();
Thread.currentThread().interrupt();
}
stop()/suspend()/resume()volatile boolean 標誌位 + interrupt() 雙重保障InterruptedException 後 必須退出或恢復中斷shutdown() 方法封裝停止邏輯,調用 join() 等待結束shutdown() → awaitTermination() → shutdownNow() 標準流程