Java中主線程如何捕獲子線程拋出的異常


首先明確線程代碼的邊界。其實很簡單,Runnable接口的run方法所界定的邊界就可以看作是線程代碼的邊界。Runnable接口中run方法原型如下:

public void run();

而所有的具體線程都實現這個方法,所以這里就明確了一點,線程代碼不能拋出任何checked異常。所有的線程中的checked異常都只能被線程本身消化掉。:) 這樣本身也是符合線程的設計理念的,線程本身就是被看作獨立的執行片斷,它應該對自己負責,所以由它來消化所有的checked異常是很正常的。
這樣就回答了樓主的第一個問題:checked異常一定要在線程內部消化。

但是,線程代碼中是可以拋出錯誤(Error)和運行級別異常(RuntimeException)的。Error俺們可以忽略,因為通常Error是應該留給vm的,而RuntimeException確是比較正常的,如果在運行過程中滿足了某種條件導致線程必須中斷,可以選擇使用拋出運行級別異常來處理,如下:

public void run() {
if (...) throw new RuntimeException();
}

當線程代碼拋出運行級別異常之后,線程會中斷。:)這點java中解釋得很清楚:
@see Thread
All threads that are not daemon threads have died, either by returning from the call to the run method or “by throwing an exception that propagates beyond the run method”.
但是對於invoke此線程的主線程會產生什么影響呢?主線程不受這個影響,不會處理這個RuntimeException,而且根本不能catch到這個異常。會繼續執行自己的代碼 :)
所以得到結論:線程方法的異常只能自己來處理。



但是,給某個thread設置一個UncaughtExceptionHandler,可以確保在該線程出現異常時能通過回調UncaughtExceptionHandler接口的public void uncaughtException(Thread t, Throwable e) 方法來處理異常,這樣的好處或者說目的是可以在線程代碼邊界之外(Thread的run()方法之外),有一個地方能處理未捕獲異常。但是要特別明確的是:雖然是在回調方法中處理異常,但這個回調方法在執行時依然還在拋出異常的這個線程中!另外還要特別說明一點:如果線程是通過線程池創建,線程異常發生時UncaughtExceptionHandler接口不一定會立即回調。代碼示例如下:

package study20170103;

/** * Created by apple on 17/1/3. */
public class ThreadTest extends ThreadGroup{

    private ThreadTest(){
        super("ThreadTest");
    }


    public static void main(String[] args) {
        new Thread(new ThreadTest(),new Runnable() {//傳入繼承ThreadGroup的類對象
            @Override
            public void run() {
                throw new NullPointerException();//只能拋出unchecked異常
            }
        }).start();
    }

    public   void   uncaughtException(Thread   thread,   Throwable   exception)
    {
        /** * 當線程拋出unckecked異常時,系統會自動調用該函數,但是是在拋出異常的線程內執行 */
        System.out.println(thread.getId());
        exception.printStackTrace();//example, print stack trace
    }
}


比之上述方法,還有一種編程上的處理方式可以借鑒,即,有時候主線程的調用方可能只是想知道子線程執行過程中發生過哪些異常,而不一定會處理或是立即處理,那么發起子線程的方法可以把子線程拋出的異常實例收集起來作為一個Exception的List返回給調用方,由調用方來根據異常情況決定如何應對。不過要特別注意的是,此時子線程早以終結。

線程設計的理念:“線程的問題應該線程自己本身來解決,而不要委托到外部。”


免責聲明!

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



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