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

Java 多線程系列(七):線程停止的正確姿勢與常見誤區

     編輯:Java 綜合教學

Java 多線程系列(七):線程停止的正確姿勢與常見誤區

Java 中無安全的強制停止線程 API(stop()、suspend()、resume() 均已棄用)。本文系統總結三種標準停止方式,並通過實驗驗證各種場景下的行為差異。

三種標準停止方式

  1. 標誌位模式:共享 volatile boolean 變量,線程定期檢查並主動退出。
  2. 中斷模式:調用 thread.interrupt(),線程通過 isInterrupted() 或捕獲 InterruptedException 響應。
  3. 異常退出模式:在中斷點拋出自定義異常終止 run() 方法。

核心 API 行為對比

方法 作用對象 清除中斷標誌 適用場景
Thread.interrupted() 當前線程 是 靜態工具方法,通常用於內部邏輯判斷
thread.isInterrupted() 指定線程 否 外部監控線程狀態,推薦使用
thread.interrupt() 指定線程 設置標誌為 true 請求線程停止

場景實驗與代碼模式

1. 普通運行線程:輪詢中斷標誌

public class Worker extends Thread {
    @Override
    public void run() {
        while (!Thread.currentThread().isInterrupted()) { // 推薦使用實例方法
            // 業務邏輯
            System.out.println("Working... " + System.currentTimeMillis());
        }
        System.out.println("線程正常退出");
    }
}

// 測試
Worker w = new Worker();
w.start();
Thread.sleep(2000);
w.interrupt(); // 請求停止

2. 含阻塞調用(sleep/wait/join)的線程

阻塞方法會拋出 InterruptedException 並清除中斷標誌,需捕獲異常後重新設置標誌或直接退出:

@Override
public void run() {
    try {
        while (!isInterrupted()) {
            Thread.sleep(1000); // 可能拋出 InterruptedException
        }
    } catch (InterruptedException e) {
        // 方案A:重新設置中斷標誌供上層調用者感知
        Thread.currentThread().interrupt();
        // 方案B:直接退出(常見於獨立線程)
        System.out.println("檢測到中斷,退出運行");
    }
}

3. I/O 阻塞場景(Socket/文件讀寫)

傳統阻塞 I/O 不響應中斷,需:

  • 關閉底層資源(socket.close())觸發異常退出
  • 遷移至 NIO 非阻塞模式或 InterruptibleChannel

4. 使用 return 而非異常控制流

while (true) {
    if (Thread.currentThread().isInterrupted()) {
        System.out.println("收到停止信號,return 退出");
        return; // 乾淨退出 run()
    }
    // 業務處理
}

棄用方法危害演示

stop() 暴力終止

  • 拋出 ThreadDeath(Error 子類),通常不被捕獲
  • 強制釋放所有鎖 → 導致數據不一致、對象處於損壞狀態
  • 可能遺留文件句柄、數據庫連接未關閉

停止策略決策樹

需要停止線程
    │
    ├─ 能否修改線程代碼?
    │   ├─ 是 → 採用中斷模式(interrupt + isInterrupted/InterruptedException)
    │   └─ 否(第三方庫/不可控代碼)
    │       ├─ 線程是否在阻塞 I/O?
    │       │   ├─ 是 → 關閉底層資源(Socket/Channel/InputStream)
    │       │   └─ 否 → 僅能依賴線程自然結束或進程級隔離
    │       └─ 考慮未來重構為可中斷設計

生產環境最佳實踐

  1. 所有可長期運行線程實現 InterruptedException 友好處理
  2. 使用 ExecutorService 管理線程生命周期,調用 shutdown()/shutdownNow()
  3. 業務代碼定期檢查 Thread.currentThread().isInterrupted()
  4. 捕獲 InterruptedException 後:重新設置中斷標誌 或 封裝為業務異常拋出
  5. 避免吞噬中斷異常(catch (InterruptedException e) {})
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved