在线不卡日本ⅴ一区v二区_精品一区二区中文字幕_天堂v在线视频_亚洲五月天婷婷中文网站

  • <menu id="lky3g"></menu>
  • <style id="lky3g"></style>
    <pre id="lky3g"><tt id="lky3g"></tt></pre>

    Java子線程中的異常處理(通用)

    在普通的單線程程序中,捕獲異常只需要通過(guò)try … catch … finally …代碼塊就可以了。那么,在并發(fā)情況下,比如在父線程中啟動(dòng)了子線程,如何正確捕獲子線程中的異常,從而進(jìn)行相應(yīng)的處理呢?

    常見(jiàn)錯(cuò)誤

    也許有人會(huì)覺(jué)得,很簡(jiǎn)單嘛,直接在父線程啟動(dòng)子線程的地方try … catch一把就可以了,其實(shí)這是不對(duì)的。

    原因分析

    讓我們回憶一下Runnable接口的run方法的完整簽名,因?yàn)闆](méi)有標(biāo)識(shí)throws語(yǔ)句,所以方法是不會(huì)拋出checked異常的。至于RuntimeException這樣的unchecked異常,由于新線程由JVM進(jìn)行調(diào)度執(zhí)行,如果發(fā)生了異常,也不會(huì)通知到父線程。

    public abstract void run()

    解決辦法

    那么,如何正確處理子線程中的異常呢?樓主想到了3種常用方法,分享給大家。

    前2種方法都是在子線程中處理,第3種方法是在父線程中處理。

    具體用哪一種方法,取決于這個(gè)異常是否適合在子線程中處理。例如有些異常更適合由調(diào)用方(父線程)處理,那么此時(shí)就應(yīng)當(dāng)用第3種方法。

    方法一:子線程中try… catch…

    最簡(jiǎn)單有效的辦法,就是在子線程的執(zhí)行方法中,把可能發(fā)生異常的地方,用try … catch … 語(yǔ)句包起來(lái)。

    子線程代碼:

    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)沒(méi)有),則優(yōu)先使用該UncaughtExceptionHandler類;否則,如果當(dāng)前線程所屬的線程組有異常處理器,則使用線程組的UncaughtExceptionHandler;否則,使用全局默認(rèn)的DefaultUncaughtExceptionHandler;如果都沒(méi)有的話,子線程就會(huì)退出。

    注意:子線程中發(fā)生了異常,如果沒(méi)有任何類來(lái)接手處理的話,是會(huì)直接退出的,而不會(huì)記錄任何日志。

    所以,如果什么都不做的話,是會(huì)出現(xiàn)子線程任務(wù)既沒(méi)執(zhí)行成功,也沒(méi)有任何提示的“詭異”現(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 1handle exception in child thread. java.lang.RuntimeException: ChildThread exception

    方法三:通過(guò)Future的get方法捕獲異常(推薦)

    使用線程池提交一個(gè)能獲取到返回信息的方法,也就是ExecutorService.submit(Callable)

    在submit之后可以獲得一個(gè)線程執(zhí)行結(jié)果的Future對(duì)象,而如果子線程中發(fā)生異常,通過(guò)future.get()獲取返回值時(shí),可以捕獲到ExecutionException異常,從而知道子線程中發(fā)生了異常。

    子線程代碼:

    public class ChildThread implements Callable { public String call() throws Exception { System.out.println(“do something 1”); exceptionMethod(); System.out.println(“do something 2”); return “test result”; } 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 1handle exception in child thread. java.util.concurrent.ExecutionException: java.lang.RuntimeException: ChildThread1 exception

    總結(jié)

    以上就是3種通用的Java子線程異常處理方法。

    具體使用哪種,取決于異常是否適合在子線程中處理,樓主更推薦第3種方式,可以方便地在父線程中根據(jù)子線程拋出的異常做適當(dāng)?shù)奶幚恚ㄗ约禾幚?,或者忽略,或者繼續(xù)向上層調(diào)用方拋異常)。其實(shí)樓主還想到了另外幾個(gè)特定場(chǎng)景下的解決辦法,改天再分析,謝謝大家的支持~

    鄭重聲明:本文內(nèi)容及圖片均整理自互聯(lián)網(wǎng),不代表本站立場(chǎng),版權(quán)歸原作者所有,如有侵權(quán)請(qǐng)聯(lián)系管理員(admin#wlmqw.com)刪除。
    用戶投稿
    上一篇 2022年6月21日 06:33
    下一篇 2022年6月21日 06:33

    相關(guān)推薦

    聯(lián)系我們

    聯(lián)系郵箱:admin#wlmqw.com
    工作時(shí)間:周一至周五,10:30-18:30,節(jié)假日休息