Java多線程——<七>多線程的異常捕捉


一、概述

  為什么要單獨講多線程的異常捕捉呢?先看個例子:

public class ThreadException implements Runnable{
    @Override
    public void run() {
        throw new RuntimeException();
    }
    //現象:控制台打印出異常信息,並運行一段時間后才停止
    public static void main(String[] args){
        //就算把線程的執行語句放到try-catch塊中也無濟於事
        try{
            ExecutorService exec = Executors.newCachedThreadPool();
            exec.execute(new ThreadException());
        }catch(RuntimeException e){
            System.out.println("Exception has been handled!");
        }
    }
}

  在run中手動拋出了一個運行時異常,在main中啟動線程,catch語句塊中捕捉下異常,捕捉到打印一句話。運行結果如下圖:

  發現異常被拋到了控制台,沒有打印catch塊中的語句。

  結論:多線程運行不能按照順序執行過程中捕獲異常的方式來處理異常,異常會被直接拋出到控制台(由於線程的本質,使得你不能捕獲從線程中逃逸的異常。一旦異常逃逸出任務的run方法,它就會向外傳播到控制台,除非你采用特殊的形式捕獲這種異常。),這樣會讓你很頭疼,無法捕捉到異常就無法處理異常而引發的問題。

  於是,我們一定會想如何在多線程中捕捉異常呢?

二、多線程中捕捉異常

  我們來按照下面的步驟完成這次實驗:

  1.定義異常處理器

   要求,實現 Thread.UncaughtExceptionHandler的uncaughtException方法,如下:

/*
 * 第一步:定義符合線程異常處理器規范的“異常處理器”
 * 實現Thread.UncaughtExceptionHandler規范
 */
class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler{
    /*
     * Thread.UncaughtExceptionHandler.uncaughtException()會在線程因未捕獲的異常而臨近死亡時被調用
     */
    @Override
    public void uncaughtException(Thread t, Throwable e) {
        System.out.println("caught    "+e);
    }
}

 

  2.定義使用該異常處理器的線程工廠

/*
 * 第二步:定義線程工廠
 * 線程工廠用來將任務附着給線程,並給該線程綁定一個異常處理器
 */
class HanlderThreadFactory implements ThreadFactory{
    @Override
    public Thread newThread(Runnable r) {
        System.out.println(this+"creating new Thread");
        Thread t = new Thread(r);
        System.out.println("created "+t);
        t.setUncaughtExceptionHandler(new MyUncaughtExceptionHandler());//設定線程工廠的異常處理器
        System.out.println("eh="+t.getUncaughtExceptionHandler());
        return t;
    }
}

  3.定義一個任務,讓其拋出一個異常

/*
 * 第三步:我們的任務可能會拋出異常
 * 顯示的拋出一個exception
 */
class ExceptionThread implements Runnable{
    @Override
    public void run() {
        Thread t = Thread.currentThread();
        System.out.println("run() by "+t);
        System.out.println("eh = "+t.getUncaughtExceptionHandler());
        throw new RuntimeException();
    }
}

  4.調用實驗

/*
 * 第四步:使用線程工廠創建線程池,並調用其execute方法
 */
public class ThreadExceptionUncaughtExceptionHandler{
    public static void main(String[] args){
        ExecutorService exec = Executors.newCachedThreadPool(new HanlderThreadFactory());
        exec.execute(new ExceptionThread());
    }
}

  運行結果如下圖:

三、結論

  在java中要捕捉多線程產生的異常,需要自定義異常處理器,並設定到對應的線程工廠中(即第一步和第二步)。

四、拓展

  如果你知道將要在代碼中處處使用相同的異常處理器,那么更簡單的方式是在Thread類中設置一個靜態域,並將這個處理器設置為默認的未捕獲處理器。

這個處理器只有在不存在線程專有的未捕獲異常處理器的情況下才會被調用。

public static void main(String[] args){
        Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
        ExecutorService exec =Executors.newCachedThreadPool();
        exec.execute(new ExceptionThread());
}

注:以上代碼均來自《thinking in java》,內容均是自己總結,如有錯誤,歡迎大家批評指正

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM