關於Android中多線程中異常捕獲出現的問題和解決辦法

    最近有個同學問我這樣一段代碼,代碼如下:

第一段代碼是這樣的,try catch是將整個線程都放在try代碼塊中。


第二塊代碼是將線程裏面的run方法代碼塊進行try catch。



大家可能第一反應都是覺得只是try的代碼塊不一樣,範圍不一樣了而已。但是可曾想過就是這個try的地方不一樣導致了不同的結果。第一種try方式當裏面的run()方法執行時報了異常是捕獲不到的,整個程序會crash掉;而第二種 try方式程序是不會crash掉。開始我一直在想,兩個try catch方式真的只有範圍不同而已,而且第一種範圍更廣一些,爲什麼捕獲不到異常呢?


其實從一開始思考就是有出了問題,爲什麼這麼說?有沒有發現這種兩try 本質區別在哪裏?根本原因是在於這兩種try是在不同線程,第一種是在ui線程進行的,第二種是在另啓的線程中。所以這纔是導致出現上述問題的根本。我在網上找了一些官話來解釋原因是這樣說的:多線程運行不能按照順序執行過程中捕獲異常的方式來處理異常,異常會被直接拋出到控制檯(由於線程的本質,使得你不能捕獲從線程中逃逸的異常。一旦異常逃逸出任務的run方法,它就會向外傳播到控制檯,除非你採用特殊的形式捕獲這種異常)。可以這麼說try的時機與拋出異常的線程不一致,所以導致異常逃逸,從而捕獲不到,導致程序crash。


下面再給大家貼下多線程中如何去捕獲異常:

/*
 * 第一步:定義符合線程異常處理器規範的“異常處理器”
 * 實現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());
    }
}




注:以上代碼均來自《thinking in java》,如有錯誤,歡迎批評指正






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章