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

Java 多線程異常處理機制:run() 方法異常傳播與 UncaughtExceptionHandler 詳解

     編輯:Java 相關知識

run() 方法與異常的基本規則

  • Thread.run() / Runnable.run() 未聲明拋出受檢異常
  • 線程內部受檢異常必須在內部 try-catch 處理,不可向外拋出
  • 非受檢異常(RuntimeException、Error)會導致線程終止,但主線程無法捕獲,不影響其他線程
public class Test2 {
    public static void main(String[] args) throws InterruptedException {
        try {
            new A("異常線程").start();
        } catch (RuntimeException re) {
            System.out.println("主線程捕獲到子線程異常:"); // 永不執行
            re.printStackTrace();
        }
        Thread.sleep(5);
        System.out.println("主線程照常執行"); // 子線程終止不影響主線程
    }
}

class A extends Thread {
    A(String name) { super(name); }
    public void run() {
        System.out.println("run() 方法運行...");
        for (int i = 0; i < 10; i++) {
            System.out.println(getName() + " 輸出:" + i);
            if (i == 3) {
                throw new RuntimeException("run 內部拋出 Runtime 異常");
            }
        }
    }
}

輸出:

run() 方法運行...
異常線程 輸出:0
異常線程 輸出:1
異常線程 輸出:2
異常線程 輸出:3
Exception in thread "異常線程" java.lang.RuntimeException: run 內部拋出 Runtime 異常
    at testpack.A.run(Test2.java:26)
主線程照常執行

異常堆疊由 ThreadGroup.uncaughtException() 輸出,線程終止,主線程繼續。

Thread.UncaughtExceptionHandler:統一異常處理機制

JDK 1.5 引入靜態內部接口 Thread.UncaughtExceptionHandler,單方法:

void uncaughtException(Thread t, Throwable e)

三級處理器綁定優先級

  1. 線程實例級:thread.setUncaughtExceptionHandler(handler)
  2. 線程組級:ThreadGroup 實現 uncaughtException,可繼承重寫
  3. 全局默認級:Thread.setDefaultUncaughtExceptionHandler(handler)

調用順序鏈

  1. 線程實例處理器
  2. 所屬 ThreadGroup.uncaughtException()(中介,遞歸至父線程組)
  3. 全局默認處理器 Thread.getDefaultUncaughtExceptionHandler()
  4. 默認行為:非 ThreadDeath 時,System.err 輸出線程名與堆疊,線程結束

代碼示例:自定義處理器

public class Test2 {
    public static void main(String[] args) throws InterruptedException {
        ExHandler eh1 = new ExHandler("Thread默認異常處理器");
        ExHandler eh2 = new ExHandler("線程實例異常處理器");
        Thread.setDefaultUncaughtExceptionHandler(eh1);
        A a = new A("異常線程");
        a.setUncaughtExceptionHandler(eh2); // 綁定實例處理器
        a.start();
    }
}

class A extends Thread {
    A(String name) { super(name); }
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(getName() + " 輸出:" + i);
            if (i == 3) { int x = 5 / 0; } // 拋出 ArithmeticException
        }
    }
}

class ExHandler implements Thread.UncaughtExceptionHandler {
    private String name;
    ExHandler(String name) { this.name = name; }
    public void uncaughtException(Thread t, Throwable e) {
        System.out.println("這是:" + name);
        System.out.println("線程:" + t.getName() + " 異常:" + e.getMessage());
    }
}

輸出(綁定實例處理器):

run() 方法運行...
異常線程 輸出:0
異常線程 輸出:1
異常線程 輸出:2
異常線程 輸出:3
這是:線程實例異常處理器
線程: 異常線程 異常: / by zero

註釋掉實例綁定後(走全局默認):

這是:Thread默認異常處理器
線程: 異常線程 異常: / by zero

最佳實踐建議

  • 生產環境務必設置全局默認處理器,記錄日誌、報警、防止靜默失敗
  • 關鍵業務線程設置實例處理器,實現差異化處理(重試、降級、補償)
  • 避免在 run() 拋出受檢異常,內部轉為非受檢或妥善處理
  • 線程池場景下,Future.get() 可獲取異常,或實現 ThreadFactory 統一設置處理器
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved