一、子線程中的異常
- 在主線程中拋出異常會很容易的被發現,因爲程序停止繼續向下運行了;而在子線程中拋出異常,主線程會繼續執行,異常很難被發現。
/**
* 在主線程中拋出異常,程序停止繼續運行,會有異常堆棧
* 在子線程中拋出異常,主線程會繼續執行,很難發現
*/
public class ThreadExceptions {
public static void main(String[] args) throws InterruptedException {
System.out.println("主線程啓動");
Thread thread = new Thread(new Dowork());
thread.start();
Thread.sleep(1000);
System.out.println("主線程繼續執行任務");
}
}
class Dowork implements Runnable{
@Override
public void run() {
System.out.println("子線程:"+Thread.currentThread().getName());
throw new RuntimeException();
}
}
- 子線程中的異常無法用傳統的方法(try-catch)捕獲
因爲try-catch只能捕獲自己線程中的異常。
/**
* 子線程中的異常無法用傳統的方法(try-catch)捕獲
*/
public class ThreadExceptions {
public static void main(String[] args) throws InterruptedException {
System.out.println("主線程啓動");
try {
Thread thread = new Thread(new Dowork());
thread.start();
}catch (Exception e){
System.out.println("子線程拋出了異常!");
}
Thread.sleep(1000);
System.out.println("主線程繼續執行任務");
}
}
class Dowork implements Runnable{
@Override
public void run() {
System.out.println("子線程:"+Thread.currentThread().getName());
throw new RuntimeException();
}
}
- 如果不捕獲子線程中的異常,主線程會繼續執行,沒有人知道發生了異常,會造成意想不到的嚴重後果。
二、兩種捕獲子線程異常的解決方案
- 在每個run()方法中編寫try-catch(不推薦)
- 使用UncaughtExceptionHandler(推薦)
三、UncaughtExceptionHandler
1.簡介
- UncaughExceptionHandler是Thread類提供的一個異常處理器接口,它能檢測到線程因爲未捕獲異常而終止的情況並進行處理。
- UncaughtExceptionHandler異常處理器中的內容很簡單,就是調用了uncaughtException()方法。
- 異常處理器的調用策略,看一下uncaughtException()的源碼
public void uncaughtException(Thread t, Throwable e) {
// 尋找父線程,調用父線程的uncaughtException(),遞歸
if (parent != null) {
parent.uncaughtException(t, e);
} else {
// 獲取線程的默認的異常處理器:
// 如果沒有使用Thread.setDefaultUncaughtExceptionHandler()設置異常處理器,則取不到
Thread.UncaughtExceptionHandler ueh =
Thread.getDefaultUncaughtExceptionHandler();
if (ueh != null) {
// 取到了,則執行設置的異常處理器
ueh.uncaughtException(t, e);
} else if (!(e instanceof ThreadDeath)) {
// 沒取到,則打印異常信息
System.err.print("Exception in thread \""
+ t.getName() + "\" ");
e.printStackTrace(System.err);
}
}
}
- 所有,我們需要實現一個自己的異常處理器,並設置給線程,這樣當線程中有異常時,就會走我們自己的異常處理器
2.使用我們自己的異常處理器監控線程中的異常
- 自己實現異常處理器
/**
* 自己實現的異常處理器
*/
public class ThreadExceptionHandler implements Thread.UncaughtExceptionHandler{
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("線程["+t.getName()+"]異常終止:"+e.getMessage());
}
}
- 使用異常處理器
public class ThreadExceptions {
public static void main(String[] args) {
System.out.println("主線程開始執行...");
Thread.setDefaultUncaughtExceptionHandler(new ThreadExceptionHandler());
Thread thread = new Thread(new DoWorks());
thread.start();
Thread thread1 = new Thread(new DoWorks());
thread1.start();
Thread thread2 = new Thread(new DoWorks());
thread2.start();
System.out.println("主線程繼續執行...");
}
}
class DoWorks implements Runnable{
@Override
public void run() {
throw new RuntimeException("數據庫連接失敗了!");
}
}
- 效果