您好,登錄后才能下訂單哦!
這篇文章給大家介紹在Java子線程中怎么對(duì)異常進(jìn)行處理,內(nèi)容非常詳細(xì),感興趣的小伙伴們可以參考借鑒,希望對(duì)大家能有所幫助。
常見錯(cuò)誤
也許有人會(huì)覺得,很簡(jiǎn)單嘛,直接在父線程啟動(dòng)子線程的地方try ... catch一把就可以了,其實(shí)這是不對(duì)的。
原因分析
讓我們回憶一下Runnable接口的run方法的完整簽名,因?yàn)闆]有標(biāo)識(shí)throws語句,所以方法是不會(huì)拋出checked異常的。至于RuntimeException這樣的unchecked異常,由于新線程由JVM進(jìn)行調(diào)度執(zhí)行,如果發(fā)生了異常,也不會(huì)通知到父線程。
public abstract void run()
解決辦法
那么,如何在父線程中捕獲來自子線程的異常呢?樓主想到了3種常用方法,分享給大家。
方法一:子線程中try... catch...
最簡(jiǎn)單有效的辦法,就是在子線程的方法中,把可能發(fā)生異常的地方,用try ... catch ... 語句包起來。子線程代碼:
public class ChildThread implements Runnable { public void run() { doSomething1(); try { // 可能發(fā)生異常的方法 exceptionMethod(); } catch (Exception e) { // 處理異常 System.out.println(String.format("handle exception in child thread. %s", e)); } doSomething2(); } }
方法二:為線程設(shè)置異常處理器UncaughtExceptionHandler
為線程設(shè)置異常處理器。具體做法可以是以下幾種:
(1)Thread.setUncaughtExceptionHandler設(shè)置當(dāng)前線程的異常處理器
(2)Thread.setDefaultUncaughtExceptionHandler為整個(gè)程序設(shè)置默認(rèn)的異常處理器如果當(dāng)前線程有異常處理器(默認(rèn)沒有),則優(yōu)先使用該UncaughtExceptionHandler類;否則,如果當(dāng)前線程所屬的線程組有異常處理器,則使用線程組的ExceptionHandler;否則,使用全局默認(rèn)的DefaultUncaughtExceptionHandler;如果都沒有的話,子線程就會(huì)退出。
注意:子線程中發(fā)生了異常,如果沒有任何類來接手處理的話,是會(huì)直接退出的,而不會(huì)留下打印任何日志。所以,如果什么都不做的話,是會(huì)出現(xiàn)子線程任務(wù)既沒執(zhí)行,也沒有任何日志提示的“詭異”現(xiàn)象的。
設(shè)置當(dāng)前線程的異常處理器:
public class ChildThread implements Runnable { private static ChildThreadExceptionHandler exceptionHandler; static { exceptionHandler = new ChildThreadExceptionHandler(); } public void run() { Thread.currentThread().setUncaughtExceptionHandler(exceptionHandler); System.out.println("do something 1"); exceptionMethod(); System.out.println("do something 2"); } public static class ChildThreadExceptionHandler implements Thread.UncaughtExceptionHandler { public void uncaughtException(Thread t, Throwable e) { System.out.println(String.format("handle exception in child thread. %s", e)); } } }
或者,設(shè)置所有線程的默認(rèn)異常處理器
public class ChildThread implements Runnable { private static ChildThreadExceptionHandler exceptionHandler; static { exceptionHandler = new ChildThreadExceptionHandler(); Thread.setDefaultUncaughtExceptionHandler(exceptionHandler); } public void run() { System.out.println("do something 1"); exceptionMethod(); System.out.println("do something 2"); } private void exceptionMethod() { throw new RuntimeException("ChildThread exception"); } public static class ChildThreadExceptionHandler implements Thread.UncaughtExceptionHandler { public void uncaughtException(Thread t, Throwable e) { System.out.println(String.format("handle exception in child thread. %s", e)); } } }
命令行輸出:do something 1
handle exception in child thread. java.lang.RuntimeException: ChildThread exception
方法三,通過Future的get方法捕獲異常
使用線程池提交一個(gè)能獲取到返回信息的方法,也就是ExecutorService.submit(Callable)在submit之后可以獲得一個(gè)線程執(zhí)行結(jié)果的Future對(duì)象,而如果子線程中發(fā)生了異常,通過future.get()獲取返回值時(shí),可以捕獲到ExecutionException異常,從而知道子線程中發(fā)生了異常。
子線程代碼:
public class ChildThread implements Callable { public Object call() throws Exception { System.out.println("do something 1"); exceptionMethod(); System.out.println("do something 2"); return null; } private void exceptionMethod() { throw new RuntimeException("ChildThread1 exception"); } }
父線程代碼:
public class Main { public static void main(String[] args) { ExecutorService executorService = Executors.newFixedThreadPool(8); Future future = executorService.submit(new ChildThread()); try { future.get(); } catch (InterruptedException e) { System.out.println(String.format("handle exception in child thread. %s", e)); } catch (ExecutionException e) { System.out.println(String.format("handle exception in child thread. %s", e)); } finally { if (executorService != null) { executorService.shutdown(); } } } }
命令行輸出:do something 1
handle exception in child thread. java.util.concurrent.ExecutionException: java.lang.RuntimeException: ChildThread1 exception
關(guān)于在Java子線程中怎么對(duì)異常進(jìn)行處理就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。