[轉]Java中主執行緒如何捕獲子執行緒丟擲的異常
阿新 • • 發佈:2019-02-15
這麼來看待這個問題。首先明確執行緒程式碼的邊界。其實很簡單,Runnable介面的run方法所界定的邊界就可以看作是執行緒程式碼的邊界。Runnable介面中run方法原型如下:
<<
public void run();
>>
而所有的具體執行緒都實現這個方法,所以這裡就明確了一點,執行緒程式碼不能丟擲任何checked異常。所有的執行緒中的checked異常都只能被執行緒本身消化掉。:) 這樣本身也是符合執行緒的設計理念的,執行緒本身就是被看作獨立的執行片斷,它應該對自己負責,所以由它來消化所有的checked
<<
public void run() {
if (...) throw new RuntimeException();
}
>>
<< @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".
>>
所以得到結論:執行緒方法的異常只能自己來處理。關於最後一點,不相信的話大家可以做這麼一個試驗:
<<
public class TestThreadException extends Thread {
public void run() {
throw new RuntimeException();
}
public static void main(String[] args) throws InterruptedException {
try {
new TestThreadException().start();
} catch(RuntimeException ex) {
// 看看能不能到達這裡? :)
}
Thread.sleep(1000);
// 看看能不能到達這裡? :)
}
}
>>
結果當然是捕捉不到異常了。
記不得在哪裡看到的程式碼,可以處理到執行緒中丟擲的RuntimeException:
public class ApplicationLoader extends ThreadGroup
{
private ApplicationLoader()
{
super("ApplicationLoader");
}
public static void main(String[] args)
{
Runnable appStarter = new Runnable()
{
public void run()
{
//invoke your application (i.e.MySystem.main(args)
throw new NullPointerException(); //example, throw a runtime exception
}
};
new Thread(new ApplicationLoader(), appStarter).start();
}
//We overload this method from our parent
//ThreadGroup , which will make sure that it
//gets called when it needs to be. This is
//where the magic occurs.
public void uncaughtException(Thread thread, Throwable exception)
{
//Handle the error/exception.
//Typical operations might be displaying a
//useful dialog, writing to an event log, etc.
exception.printStackTrace();//example, print stack trace
}
}
呵呵,uncaughtException好像是唯一能夠處理執行緒丟擲的uncaught異常的入口。看來還是有細心人啊。確實如此,通過ThreadGroup的uncaughtException方法還是有處理的機會。當執行緒丟擲uncaughtException的時候,JVM會呼叫ThreadGroup的此方法。預設的處理如下:
<<
public void uncaughtException(Thread t, Throwable e) {
if (parent != null) {
parent.uncaughtException(t, e);
} else if (!(e instanceof ThreadDeath)) {
e.printStackTrace(System.err);
}
}
>>
每個Thread都會有一個ThreadGroup物件,可以通過Thread.getThreadGroup()方法得到,提供了上述預設的uncaught異常處理方法。上面沒有提這點,因為俺認為在正常的情況下,這個方法的處理情況就已經足夠了。還是那個執行緒設計的理念:“執行緒的問題應該執行緒自己本身來解決,而不要委託到外部。”通常情況下,外部不需要處理執行緒的異常。當然也有例外。:)
以上是我在網上看到的一些資料,自己在做的時候沒辦法,只好設計靜態變量了,(當然,用這種方法的前提是在主執行緒中加入thread.join()方法,那樣主執行緒要等待子執行緒完成後再執行下一步,不然主執行緒都跑完了,子執行緒才出錯,咋個都捕捉不到了)
程式也怪得很,竟然要求子執行緒拋異常後,要停掉主執行緒,也是沒有現成的方法,最後自己定義的靜態變數。