最近有個同學問我這樣一段代碼,代碼如下:
第一段代碼是這樣的,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》,如有錯誤,歡迎批評指正