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

Java 線程中斷機制深度解析:interrupt()、isInterrupted()、InterruptedException 的正確協作模式

     編輯:Java 相關知識

中斷不是強制終止,而是「禮貌請求」

Java 沒有 Thread.stop()(已棄用,不安全)。中斷是一種協作機制:發起方調用 interrupt() 設置標誌位,被中斷方主動檢查並決定如何響應(退出、清理、拋異常、忽略)。

三大核心 API

方法類型作用關鍵行為
thread.interrupt()實例請求中斷設置線程中斷狀態為 true;若線程阻塞在 sleep/wait/join,拋 InterruptedException 並清除中斷狀態
thread.isInterrupted()實例查詢狀態返回中斷狀態,**不清除**
Thread.interrupted()靜態查詢並清除返回當前線程中斷狀態,**並清除為 false**

標準響應模式:三種場景

場景一:計算密集型循環(無阻塞調用)


while (!Thread.currentThread().isInterrupted()) {
    // 執行計算任務
    if (checkCondition()) doSomething();
}
// 退出循環後可選拋出異常或正常結束

主動輪詢 isInterrupted(),不拋異常,乾淨退出。

場景二:阻塞調用(sleep/wait/join/IO)


try {
    while (true) {
        TimeUnit.SECONDS.sleep(1); // 或 blockingQueue.take()
        doPeriodicWork();
    }
} catch (InterruptedException e) {
    Thread.currentThread().interrupt(); // 重置中斷狀態!關鍵步驟
    // 清理資源、記錄日誌
    return; // 或 throw new RuntimeException(e)
}

鐵律:捕獲 InterruptedException 後必須重置中斷狀態(Thread.currentThread().interrupt()),否則上層調用者無法感知中斷請求。

場景三:不可中斷的阻塞(舊版 IO、鎖等待)

  • synchronized 獲取鎖:不可中斷,只能用 Lock.lockInterruptibly();
  • 傳統 InputStream.read():不可中斷,需關閉 Socket/Stream 觸發異常;
  • NIO Channel / Selector:支持中斷,close() 會喚醒並拋 ClosedByInterruptException。

實戰 Demo:素數生成器 5 秒後優雅停止


class PrimeGenerator extends Thread {
    @Override public void run() {
        long num = 1;
        while (!isInterrupted()) { // 場景一:主動檢查
            if (isPrime(num)) System.out.println("Prime: " + num);
            num++;
        }
        System.out.println("PrimeGenerator 收到中斷,優雅退出");
    }
    private boolean isPrime(long n) {
        if (n < 2) return false;
        for (long i = 2; i * i <= n; i++) if (n % i == 0) return false;
        return true;
    }
}

public class InterruptDemo {
    public static void main(String[] args) throws InterruptedException {
        PrimeGenerator gen = new PrimeGenerator();
        gen.start();
        TimeUnit.SECONDS.sleep(5);
        gen.interrupt(); // 發起中斷請求
        gen.join();      // 等待線程實際結束
        System.out.println("主線程結束");
    }
}

線程池中的中斷傳遞


ExecutorService pool = Executors.newFixedThreadPool(10);
Future future = pool.submit(() -> {
    while (!Thread.currentThread().isInterrupted()) { /* work */ }
});

// 取消任務
future.cancel(true); // true = mayInterruptIfRunning -> 調用 thread.interrupt()

// 關閉線程池
pool.shutdown(); // 拒絕新任務,等待現有任務完成
pool.shutdownNow(); // 嘗試中斷正在執行的任務,返回未執行任務列表

關鍵:future.cancel(true) 和 shutdownNow() 都依賴任務代碼正確響應中斷(檢查標誌或拋異常)。

常見錯誤與反模式

錯誤代碼後果修正
catch (InterruptedException e) { log.error(e); }吞掉中斷,線程繼續跑,調用者以為已取消捕獲後 Thread.currentThread().interrupt(); 重置狀態
while (true) { ... } // 無檢查中斷請求被忽略,線程永不退出循環條件加 !isInterrupted()
Thread.interrupted() 用於實例線程檢查誤清除當前線程(主線程)狀態,非目標線程用 thread.isInterrupted()
依賴 Thread.stop() / destroy()破壞鎖一致性,數據損壞,JDK 9+ 直接報錯嚴禁使用,僅用中斷協作

總結:中斷協作三部曲

  1. 發起:thread.interrupt() / future.cancel(true) / executor.shutdownNow();
  2. 感知:阻塞方法拋 InterruptedException / 輪詢 isInterrupted();
  3. 響應:清理資源、重置中斷狀態(Thread.currentThread().interrupt())、拋異常或正常返回。

掌握中斷機制,是編寫可取消、可關閉、優雅降級併發程序的基石。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved