Java多線程:7.線程的異常處理

一、子線程中的異常

  • 在主線程中拋出異常會很容易的被發現,因爲程序停止繼續向下運行了;而在子線程中拋出異常,主線程會繼續執行,異常很難被發現。
/**
 * 在主線程中拋出異常,程序停止繼續運行,會有異常堆棧
 * 在子線程中拋出異常,主線程會繼續執行,很難發現
 */
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("數據庫連接失敗了!");
    }
}
  • 效果
    在這裏插入圖片描述
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章