最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java線程池執(zhí)行過(guò)程中遇到異常的原因和解決辦法

 更新時(shí)間:2025年10月11日 09:38:52   作者:程序員小假  
當(dāng)線程池中線程頻繁出現(xiàn)未捕獲的異常,那線程的復(fù)用率就大大降低了,需要不斷地創(chuàng)建新線程,所以本文通過(guò)詳細(xì)的代碼給大家介紹了Java線程池執(zhí)行過(guò)程中遇到異常的解決辦法,需要的朋友可以參考下

線程遇到未處理的異常就結(jié)束了

這個(gè)好理解,當(dāng)線程出現(xiàn)未捕獲異常的時(shí)候就執(zhí)行不下去了,留給它的就是垃圾回收了。 

線程池中線程頻繁出現(xiàn)未捕獲異常

當(dāng)線程池中線程頻繁出現(xiàn)未捕獲的異常,那線程的復(fù)用率就大大降低了,需要不斷地創(chuàng)建新線程。
做個(gè)實(shí)驗(yàn):

public class ThreadExecutor {
    private ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS,
                                                                           new ArrayBlockingQueue<>(200), new ThreadFactoryBuilder().setNameFormat("customThread %d").build());
    @Test
    public void test() {
        IntStream.rangeClosed(1, 5).forEach(i -> {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            threadPoolExecutor.execute(() -> {
                int j = 1/0;
            });});
    }
}

新建一個(gè)只有一個(gè)線程的線程池,每隔0.1s提交一個(gè)任務(wù),任務(wù)中是一個(gè)1/0的計(jì)算。

Exception in thread "customThread 0" java.lang.ArithmeticException: / by zero
 at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25)
 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
 at java.lang.Thread.run(Thread.java:748)
Exception in thread "customThread 1" java.lang.ArithmeticException: / by zero
 at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25)
 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
 at java.lang.Thread.run(Thread.java:748)
Exception in thread "customThread 2" java.lang.ArithmeticException: / by zero
 at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25)
 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
 at java.lang.Thread.run(Thread.java:748)
Exception in thread "customThread 3" java.lang.ArithmeticException: / by zero
 at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25)
 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
 at java.lang.Thread.run(Thread.java:748)
Exception in thread "customThread 4" java.lang.ArithmeticException: / by zero
 at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25)
 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
 at java.lang.Thread.run(Thread.java:748)
Exception in thread "customThread 5" java.lang.ArithmeticException: / by zero
 at thread.ThreadExecutor.lambda$null$0(ThreadExecutor.java:25)
 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
 at java.lang.Thread.run(Thread.java:748)

可見(jiàn)每次執(zhí)行的線程都不一樣,之前的線程都沒(méi)有復(fù)用。原因是因?yàn)槌霈F(xiàn)了未捕獲的異常。
把異常捕獲試試:

public class ThreadExecutor {
    private ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS,
                                                                           new ArrayBlockingQueue<>(200), new ThreadFactoryBuilder().setNameFormat("customThread %d").build());
    @Test
    public void test() {
        IntStream.rangeClosed(1, 5).forEach(i -> {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            threadPoolExecutor.execute(() -> {
                try {
                    int j = 1 / 0;
                } catch (Exception e) {
                    System.out.println(Thread.currentThread().getName() +" "+ e.getMessage());
                }
            });
        });
    }
}
customThread 0 / by zero
customThread 0 / by zero
customThread 0 / by zero
customThread 0 / by zero
customThread 0 / by zero

可見(jiàn)當(dāng)異常捕獲了,線程就可以復(fù)用了。 

問(wèn)題來(lái)了,代碼中異常不可能全部捕獲

如果要捕獲那些沒(méi)被業(yè)務(wù)代碼捕獲的異常,可以設(shè)置Thread類的uncaughtExceptionHandler屬性。這時(shí)使用ThreadFactoryBuilder會(huì)比較方便,ThreadFactoryBuilder是guava提供的ThreadFactory生成器。

new ThreadFactoryBuilder()
    .setNameFormat("customThread %d")
    .setUncaughtExceptionHandler((t, e) -> System.out.println(t.getName() + "發(fā)生異常" + e.getCause()))
    .build()

修改之后:

public class ThreadExecutor {
    private static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS,
                                                                                  new ArrayBlockingQueue<>(200),
                                                                                  new ThreadFactoryBuilder()
                                                                                  .setNameFormat("customThread %d")
                                                                                  .setUncaughtExceptionHandler((t, e) -> System.out.println("UncaughtExceptionHandler捕獲到:" + t.getName() + "發(fā)生異常" + e.getMessage()))
                                                                                  .build());
    @Test
    public void test() {
        IntStream.rangeClosed(1, 5).forEach(i -> {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            threadPoolExecutor.execute(() -> {
                System.out.println("線程" + Thread.currentThread().getName() + "執(zhí)行");
                int j = 1 / 0;
            });
        });
    }
}
線程customThread 0執(zhí)行
UncaughtExceptionHandler捕獲到:customThread 0發(fā)生異常/ by zero
線程customThread 1執(zhí)行
UncaughtExceptionHandler捕獲到:customThread 1發(fā)生異常/ by zero
線程customThread 2執(zhí)行
UncaughtExceptionHandler捕獲到:customThread 2發(fā)生異常/ by zero
線程customThread 3執(zhí)行
UncaughtExceptionHandler捕獲到:customThread 3發(fā)生異常/ by zero
線程customThread 4執(zhí)行
UncaughtExceptionHandler捕獲到:customThread 4發(fā)生異常/ by zero

可見(jiàn),結(jié)果并不是想象的那樣,線程池中原有的線程沒(méi)有復(fù)用!所以通過(guò)UncaughtExceptionHandler想將異常吞掉使線程復(fù)用這招貌似行不通。它只是做了一層異常的保底處理。
excute改成submit試試

public class ThreadExecutor {
    private static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS,
                                                                                  new ArrayBlockingQueue<>(200),
                                                                                  new ThreadFactoryBuilder()
                                                                                  .setNameFormat("customThread %d")
                                                                                  .setUncaughtExceptionHandler((t, e) -> System.out.println("UncaughtExceptionHandler捕獲到:" + t.getName() + "發(fā)生異常" + e.getMessage()))
                                                                                  .build());
    @Test
    public void test() {
        IntStream.rangeClosed(1, 5).forEach(i -> {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Future<?> future = threadPoolExecutor.submit(() -> {
                System.out.println("線程" + Thread.currentThread().getName() + "執(zhí)行");
                int j = 1 / 0;
            });
            try {
                future.get();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        });
    }
}
線程customThread 0執(zhí)行
java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero
線程customThread 0執(zhí)行
java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero
線程customThread 0執(zhí)行
java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero
線程customThread 0執(zhí)行
java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero
線程customThread 0執(zhí)行
java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero

通過(guò)submit提交線程可以屏蔽線程中產(chǎn)生的異常,達(dá)到線程復(fù)用。當(dāng)get()執(zhí)行結(jié)果時(shí)異常才會(huì)拋出。
原因是通過(guò)submit提交的線程,當(dāng)發(fā)生異常時(shí),會(huì)將異常保存,待future.get();時(shí)才會(huì)拋出。
這是Futuretask的部分run()方法,看setException

public void run() {
    try {
        Callable<V> c = callable;
        if (c != null && state == NEW) {
            V result;
            boolean ran;
            try {
                result = c.call();
                ran = true;
            } catch (Throwable ex) {
                result = null;
                ran = false;
                setException(ex);
            }
            if (ran)
                set(result);
        }
    } 
}
protected void setException(Throwable t) {
    if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
        outcome = t;
        UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state
        finishCompletion();
    }
}

將異常存在outcome對(duì)象中,沒(méi)有拋出,再看get方法:

public V get() throws InterruptedException, ExecutionException {
    int s = state;
    if (s <= COMPLETING)
        s = awaitDone(false, 0L);
    return report(s);
}
private V report(int s) throws ExecutionException {
    Object x = outcome;
    if (s == NORMAL)
        return (V)x;
    if (s >= CANCELLED)
        throw new CancellationException();
    throw new ExecutionException((Throwable)x);
}

當(dāng)outcome是異常時(shí)才拋出。 

總結(jié)

1、線程池中線程中異常盡量手動(dòng)捕獲

2、通過(guò)設(shè)置ThreadFactoryUncaughtExceptionHandler可以對(duì)未捕獲的異常做保底處理,通過(guò)execute提交任務(wù),線程依然會(huì)中斷,而通過(guò)submit提交任務(wù),可以獲取線程執(zhí)行結(jié)果,線程異常會(huì)在get執(zhí)行結(jié)果時(shí)拋出。

以上就是Java線程池執(zhí)行過(guò)程中遇到異常的原因和解決辦法的詳細(xì)內(nèi)容,更多關(guān)于Java線程池執(zhí)行遇到異常的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java?swing實(shí)現(xiàn)應(yīng)用程序?qū)?shù)據(jù)庫(kù)的訪問(wèn)問(wèn)題

    Java?swing實(shí)現(xiàn)應(yīng)用程序?qū)?shù)據(jù)庫(kù)的訪問(wèn)問(wèn)題

    這篇文章主要介紹了Java?swing實(shí)現(xiàn)應(yīng)用程序?qū)?shù)據(jù)庫(kù)的訪問(wèn),本次實(shí)驗(yàn)需要做一個(gè)GUI界面和一個(gè)連接查詢功能,在論壇上借鑒了其他大佬獲取網(wǎng)站內(nèi)容的部分代碼,然后自己做了一個(gè)及其簡(jiǎn)陋的swing界面,算是把這個(gè)實(shí)驗(yàn)完成了,需要的朋友可以參考下
    2022-09-09
  • MyBatis深入解讀懶加載的實(shí)現(xiàn)

    MyBatis深入解讀懶加載的實(shí)現(xiàn)

    顧名思義,懶加載就是因?yàn)橥祽辛?,懶得加載了,只有使用的時(shí)候才進(jìn)行加載。其實(shí),懶加載也加延遲加載,主要以應(yīng)用與Mybatis的關(guān)聯(lián)查詢,按照設(shè)置的延遲規(guī)則,推遲對(duì)延遲對(duì)關(guān)聯(lián)對(duì)象的select查詢
    2022-04-04
  • Java中的讀寫鎖ReentrantReadWriteLock源碼分析

    Java中的讀寫鎖ReentrantReadWriteLock源碼分析

    這篇文章主要介紹了Java中的讀寫鎖ReentrantReadWriteLock源碼分析,ReentrantReadWriteLock 分為讀鎖和寫鎖兩個(gè)實(shí)例,讀鎖是共享鎖,可被多個(gè)線程同時(shí)使用,寫鎖是獨(dú)占鎖,持有寫鎖的線程可以繼續(xù)獲取讀鎖,反之不行,需要的朋友可以參考下
    2023-12-12
  • 詳解java.lang.NumberFormatException錯(cuò)誤及解決辦法

    詳解java.lang.NumberFormatException錯(cuò)誤及解決辦法

    這篇文章主要介紹了詳解java.lang.NumberFormatException錯(cuò)誤及解決辦法,本文詳解的介紹了錯(cuò)誤的解決方法,感興趣的可以一起來(lái)了解一下
    2020-05-05
  • Java面試Logback打印日志如何獲取當(dāng)前方法名稱題解

    Java面試Logback打印日志如何獲取當(dāng)前方法名稱題解

    這篇文章主要為大家介紹了Java面試Logback打印日志如何獲取當(dāng)前方法名稱題解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-11-11
  • Java 連接Access數(shù)據(jù)庫(kù)的兩種方式

    Java 連接Access數(shù)據(jù)庫(kù)的兩種方式

    這篇文章主要介紹了Java 連接Access數(shù)據(jù)庫(kù)的兩種方式,本文著重講解使用JDBC連接操作Access數(shù)據(jù)庫(kù),需要的朋友可以參考下
    2015-06-06
  • java簡(jiǎn)單實(shí)現(xiàn)用語(yǔ)音讀txt文檔方法總結(jié)

    java簡(jiǎn)單實(shí)現(xiàn)用語(yǔ)音讀txt文檔方法總結(jié)

    在本篇文章里小編給大家整理了關(guān)于java簡(jiǎn)單實(shí)現(xiàn)用語(yǔ)音讀txt文檔的詳細(xì)方法總結(jié),有需要的朋友們參考下。
    2019-06-06
  • Java中數(shù)據(jù)庫(kù)常用的兩把鎖之樂(lè)觀鎖和悲觀鎖

    Java中數(shù)據(jù)庫(kù)常用的兩把鎖之樂(lè)觀鎖和悲觀鎖

    這篇文章主要介紹了數(shù)據(jù)庫(kù)常用的兩把鎖之樂(lè)觀鎖和悲觀鎖,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • SpringBoot集成Redisson實(shí)現(xiàn)消息隊(duì)列的示例代碼

    SpringBoot集成Redisson實(shí)現(xiàn)消息隊(duì)列的示例代碼

    本文介紹了如何在SpringBoot中通過(guò)集成Redisson來(lái)實(shí)現(xiàn)消息隊(duì)列的功能,包括RedisQueue、RedisQueueInit、RedisQueueListener、RedisQueueService等相關(guān)組件的實(shí)現(xiàn)和測(cè)試,感興趣的可以了解一下
    2024-10-10
  • 一篇清晰易懂的Java 8徹底卸載與清理教程

    一篇清晰易懂的Java 8徹底卸載與清理教程

    這篇文章主要介紹了Java 8徹底卸載與清理的相關(guān)資料,包括卸載程序、刪除殘留文件、清理環(huán)境變量及注冊(cè)表,最后通過(guò)命令驗(yàn)證卸載是否成功,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2025-05-05

最新評(píng)論

麻城市| 宁津县| 偏关县| 天峻县| 永州市| 富民县| 内黄县| 大英县| 邢台市| 六盘水市| 社旗县| 二连浩特市| 蛟河市| 庐江县| 重庆市| 应用必备| 沂源县| 安塞县| 通州区| 卫辉市| 稻城县| 淮安市| 新巴尔虎右旗| 嫩江县| 吉木乃县| 上林县| 岑溪市| 霍林郭勒市| 汽车| 江都市| 天水市| 澎湖县| 新疆| 九江市| 遵义市| 望城县| 如皋市| 桑植县| 周口市| 延川县| 章丘市|