一:為什么要單獨講多線程的異常捕捉呢?
先看個例子:
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());}
以上就是本文針對Java多線程之多線程的異常捕捉的全部內容,本文如有理解錯誤地方,歡迎批評改正。
新聞熱點
疑難解答