首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 線程優雅終止的三種標準模式:標誌位、中斷機制、資源關閉

     編輯:Java 相關知識

核心原則:不使用 stop()/suspend()/resume()

這三個方法已棄用:stop() 導致鎖強制釋放,數據不一致;suspend()/resume() 極易死鎖。正確終止需協作式:線程主動檢查終止信號並安全退出。

模式一:volatile 標誌位(非阻塞任務)

public class FlagTask extends Thread {
    // volatile 保證可見性,防止 JIT 優化緩存
    private volatile boolean running = true;
    
    public void shutdown() {
        running = false; // 請求終止
    }
    
    @Override
    public void run() {
        while (running) { // 輪詢檢查
            // 執行非阻塞業務邏輯
            doWork();
        }
        // 清理資源、記錄日誌
        cleanup();
    }
    
    private void doWork() { /* ... */ }
    private void cleanup() { /* ... */ }
}
  • 適用:計算密集型、短耗時循環任務
  • 缺點:無法中斷阻塞調用(IO、sleep、wait、LockSupport.park)

模式二:interrupt() 中斷機制(可中斷阻塞)

public class InterruptibleTask implements Runnable {
    @Override
    public void run() {
        try {
            while (!Thread.currentThread().isInterrupted()) { // 檢查中斷狀態
                // 可中斷阻塞操作:sleep、wait、join、Channel IO、Lock.lockInterruptibly
                TimeUnit.SECONDS.sleep(1); 
                doWork();
            }
        } catch (InterruptedException e) {
            // 睡眠中被中斷:異常捕獲後中斷狀態被清除
            Thread.currentThread().interrupt(); // 重新設置中斷標誌(良好習慣)
        } finally {
            cleanup(); // 確保資源釋放
        }
    }
    
    private void doWork() { /* ... */ }
    private void cleanup() { /* ... */ }
}

// 使用
Thread t = new Thread(new InterruptibleTask());
t.start();
// ... 
t.interrupt(); // 發送中斷請求
  • interrupt() 僅設置中斷標誌,不直接停止線程
  • 阻塞方法收到中斷拋出 InterruptedException 並清除標誌
  • 非阻塞代碼需主動調用 Thread.interrupted() 或 isInterrupted() 檢查
  • 適用:定時任務、網絡調用、鎖等待、Channel IO

模式三:關閉底層資源(不可中斷阻塞:傳統 IO、ServerSocket.accept)

public class SocketServerTask extends Thread {
    private volatile ServerSocket serverSocket;
    
    @Override
    public void run() {
        try {
            serverSocket = new ServerSocket(8080);
            while (!Thread.currentThread().isInterrupted()) {
                Socket client = serverSocket.accept(); // 阻塞,不可中斷
                handleClient(client);
            }
        } catch (IOException e) {
            // ServerSocket.close() 會導致 accept() 拋出 SocketException
            if (!Thread.currentThread().isInterrupted()) {
                log.error("ServerSocket error", e);
            }
        }
    }
    
    public void shutdown() {
        try {
            if (serverSocket != null) {
                serverSocket.close(); // 觸發 accept() 異常退出
            }
        } catch (IOException e) {
            log.error("Close server socket failed", e);
        }
        this.interrupt(); // 輔助中斷
    }
    
    private void handleClient(Socket client) { /* ... */ }
}
  • 傳統 BIO ServerSocket.accept()/InputStream.read() 不響應中斷
  • 關閉底層資源(Socket、FileDescriptor、Connection)強制釋放阻塞
  • NIO Selector/Channel 原生支持中斷,優先選用

綜合最佳實踐模板

public abstract class GracefulTask implements Runnable {
    private volatile boolean shutdownRequested = false;
    
    public final void shutdown() {
        shutdownRequested = true;
        interrupt();           // 嘗試中斷阻塞
        closeResources();      // 關閉底層資源
    }
    
    protected boolean isShutdownRequested() {
        return shutdownRequested || Thread.currentThread().isInterrupted();
    }
    
    protected abstract void doWork() throws Exception;
    protected abstract void closeResources();
    
    @Override
    public final void run() {
        try {
            while (!isShutdownRequested()) {
                doWork();
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } catch (Exception e) {
            log.error("Task error", e);
        } finally {
            closeResources();
        }
    }
}

場景選擇決策樹

  1. 純計算/非阻塞循環 → volatile boolean
  2. 涉及 sleep/wait/join/Lock/Channel → interrupt()
  3. 傳統 BIO (ServerSocket/InputStream) → close() 資源 + interrupt()
  4. 第三方庫無中斷支持 → 線程池 Future.cancel(true) + 超時監控
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved