Java多線程之多線程異常捕捉
一:為什么要單獨(dú)講多線程的異常捕捉呢?
先看個(gè)例子:
public class ThreadException implements Runnable{ @Override public void run() { throw new RuntimeException(); } //現(xiàn)象:控制臺(tái)打印出異常信息,并運(yùn)行一段時(shí)間后才停止 public static void main(String[] args){ //就算把線程的執(zhí)行語(yǔ)句放到try-catch塊中也無(wú)濟(jì)于事 try{ ExecutorService exec = Executors.newCachedThreadPool(); exec.execute(new ThreadException()); }catch(RuntimeException e){ System.out.println("Exception has been handled!"); } } }
在run中手動(dòng)拋出了一個(gè)運(yùn)行時(shí)異常,在main中啟動(dòng)線程,catch語(yǔ)句塊中捕捉下異常,捕捉到打印一句話。運(yùn)行結(jié)果如下圖:
發(fā)現(xiàn)異常被拋到了控制臺(tái),沒有打印catch塊中的語(yǔ)句。
結(jié)論:多線程運(yùn)行不能按照順序執(zhí)行過程中捕獲異常的方式來處理異常,異常會(huì)被直接拋出到控制臺(tái)(由于線程的本質(zhì),使得你不能捕獲從線程中逃逸的異常。一旦異常逃逸出任務(wù)的run方法,它就會(huì)向外傳播到控制臺(tái),除非你采用特殊的形式捕獲這種異常。),這樣會(huì)讓你很頭疼,無(wú)法捕捉到異常就無(wú)法處理異常而引發(fā)的問題。
于是,我們一定會(huì)想如何在多線程中捕捉異常呢?
二、多線程中捕捉異常
我們來按照下面的步驟完成這次實(shí)驗(yàn):
1.定義異常處理器
要求,實(shí)現(xiàn) Thread.UncaughtExceptionHandler的uncaughtException方法,如下:
/* * 第一步:定義符合線程異常處理器規(guī)范的“異常處理器” * 實(shí)現(xiàn)Thread.UncaughtExceptionHandler規(guī)范 */ class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler{ /* * Thread.UncaughtExceptionHandler.uncaughtException()會(huì)在線程因未捕獲的異常而臨近死亡時(shí)被調(diào)用 */ @Override public void uncaughtException(Thread t, Throwable e) { System.out.println("caught "+e); } }
2.定義使用該異常處理器的線程工廠
/* * 第二步:定義線程工廠 * 線程工廠用來將任務(wù)附著給線程,并給該線程綁定一個(gè)異常處理器 */ 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());//設(shè)定線程工廠的異常處理器 System.out.println("eh="+t.getUncaughtExceptionHandler()); return t; } }
3.定義一個(gè)任務(wù),讓其拋出一個(gè)異常
/* * 第三步:我們的任務(wù)可能會(huì)拋出異常 * 顯示的拋出一個(gè)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.調(diào)用實(shí)驗(yàn)
/* * 第四步:使用線程工廠創(chuàng)建線程池,并調(diào)用其execute方法 */ public class ThreadExceptionUncaughtExceptionHandler{ public static void main(String[] args){ ExecutorService exec = Executors.newCachedThreadPool(new HanlderThreadFactory()); exec.execute(new ExceptionThread()); } }
運(yùn)行結(jié)果如下圖:
三、結(jié)論
在java中要捕捉多線程產(chǎn)生的異常,需要自定義異常處理器,并設(shè)定到對(duì)應(yīng)的線程工廠中(即第一步和第二步)。
四、拓展
如果你知道將要在代碼中處處使用相同的異常處理器,那么更簡(jiǎn)單的方式是在Thread類中設(shè)置一個(gè)靜態(tài)域,并將這個(gè)處理器設(shè)置為默認(rèn)的未捕獲處理器。
這個(gè)處理器只有在不存在線程專有的未捕獲異常處理器的情況下才會(huì)被調(diào)用。
public static void main(String[] args){ Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler()); ExecutorService exec =Executors.newCachedThreadPool(); exec.execute(new ExceptionThread()); }
以上就是本文針對(duì)Java多線程之多線程的異常捕捉的全部?jī)?nèi)容,本文如有理解錯(cuò)誤地方,歡迎批評(píng)改正。
相關(guān)文章
Java Stream的基本概念以及創(chuàng)建方法
這篇文章主要介紹了Java Stream的基本概念以及創(chuàng)建方法,幫助大家更好的理解和學(xué)習(xí)Java,感興趣的朋友可以了解下2020-08-08Spring Boot整合tk.mybatis代碼實(shí)例
這篇文章主要介紹了Spring Boot整合tk.mybatis代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-11-11MyBatis 動(dòng)態(tài)SQL之where標(biāo)簽的使用
本文主要介紹了MyBatis 動(dòng)態(tài)SQL之where標(biāo)簽,where 標(biāo)簽主要用來簡(jiǎn)化 SQL 語(yǔ)句中的條件判斷,可以自動(dòng)處理 AND/OR 條件,下面就來具體介紹一下2024-01-01JAVA得到數(shù)組中最大值和最小值的簡(jiǎn)單實(shí)例
這篇文章主要介紹了JAVA得到數(shù)組中最大值和最小值的簡(jiǎn)單實(shí)例,需要的朋友可以參考下2014-08-08JavaWeb實(shí)現(xiàn)簡(jiǎn)單文件上傳功能
這篇文章主要為大家詳細(xì)介紹了JavaWeb實(shí)現(xiàn)簡(jiǎn)單文件上傳功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-06-06mybatis TypeHandler注入spring的依賴方式
這篇文章主要介紹了mybatis TypeHandler注入spring的依賴方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01Java實(shí)現(xiàn)把窗體隱藏到系統(tǒng)托盤方法
這篇文章主要介紹了Java實(shí)現(xiàn)把窗體隱藏到系統(tǒng)托盤方法,本文直接給出核心功能代碼,需要的朋友可以參考下2015-05-05