在單線程
的開發過程中,通常採用try-catch
的方式進行異常捕獲,但是這種方式在多線程環境
中會顯得無能爲力
,而且還有可能導致一些問題的出現,比如發生異常的時候不能及時回收系統資源
,或者無法及時關閉當前的連接
…
概述
Java中有兩種異常,即已知異常(編輯器會提示捕獲或者拋出)
和未知異常(特殊情況下發生)
,由於線程中的run()
方法是不接受拋出語句的(只能內部捕獲),所以在面對未知異常
的情況,線程默認的會將堆棧跟蹤信息輸出到控制檯中(或者記錄到錯誤日誌文件中)然後退出程序。
在JDK1.5
之前,不能爲線程單獨設置或指定一個默認的UncaughtExceptionHandler
,爲了設置UncaughtExceptionHandler
,需要繼承ThreadGroup
並覆寫uncaughtException
方法。 幸運的是JDK1.5
後線程提供了一個setUncaughtExceptionHandler
方法,用來捕獲並處理因線程中拋出的未知異常
,以避免程序終止。
案例
1.首先模擬一個連接池
class ConnectionPool {
static void create() {
System.out.println("初始化連接池...");
}
static void close() {
System.out.println("關閉連接池...");
}
}
2.爲了測試需要,只是簡單模擬了一個異常
public static void main(String[] args) {
ConnectionPool.create();
try {
//有個任務需要異步執行
Thread thread = new Thread(() -> System.out.println(Integer.parseInt("ABC")), "T2");
thread.start();
} catch (Exception e) {
ConnectionPool.close();
}
}
控制檯輸出異常:
Exception in thread "T2" java.lang.NumberFormatException: For input string: "ABC"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:580)
at java.lang.Integer.parseInt(Integer.java:615)
at com.demo.sso.resource1.test.ThreadUncaughtException.lambda$main$0(ThreadUncaughtException.java:18)
at java.lang.Thread.run(Thread.java:748)
分析: 從日誌中,並未發現關閉資源應有的日誌輸出,很明顯try-catch
沒有起作用,因爲在main函數中
他是主線程
,當thread.start()
之後,主線程
的代碼與子線程
就沒半毛錢關係了,所以發生在子線程
內部的錯誤無法捕獲到。
解決方案
使用
UncaughtExceptionHandler
,這裏爲了偷懶使用了lambda
簡化了匿名內部類的寫法(也可以實現UncaughtExceptionHandler
)
public static void main(String[] args) {
ConnectionPool.create();
Thread thread = new Thread(() -> System.out.println(Integer.parseInt("ABC")), "T1");
thread.start();
thread.setUncaughtExceptionHandler((t, e) -> {
System.out.println("[線程] - [" + t.getName() + "] - [消息] - [" + e.getMessage() + "]");
ConnectionPool.close();
});
}
分析: 從日誌中可以發現錯誤信息被我們捕獲了,並且可以成功釋放資源!使用UncaughtExceptionHandler
,可以捕獲到未知異常
且記錄下自定義的日誌(默認拋出堆棧信息),具體在Zookeeper
中就有使用過,源碼爲:ZookeeperThread
,ZooKeeperCriticalThread
本文鏈接: https://blog.battcn.com/2017/10/11/java/thread/thread-uncaught-exception/
作者二維碼: