线程池中线程异常

文章探讨了Java线程池中`execute`和`submit`方法在遇到异常时的不同行为:`execute`可能导致线程被回收且异常未捕获,`submit`则能实现线程复用,异常在Future.get()时抛出。
摘要由CSDN通过智能技术生成

原文代码抄的:  自己写了点代码权当自己留存

面试官:线程池执行过程中遇到异常会发生什么,怎样处理? - 知乎

一  线程池构造函数未使用setUncaughtExceptionHandler构造

package com.text;


import com.google.common.util.concurrent.ThreadFactoryBuilder;
import org.junit.Test;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;

/**
 * 未设定 exceptionhandler
 */
public class TestUnCatchExceptionThreadPool {

    private ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 20,
            TimeUnit.SECONDS, new ArrayBlockingQueue<>(100), new ThreadFactoryBuilder().setNameFormat("current-thread-%d").build(),
            new ThreadPoolExecutor.CallerRunsPolicy());

    /**
     * 未补货的异常: 线程被回收,抛出异常  线程对象重新new
     * 输出结果如下: 抛出异常
     * Exception in thread "current-thread-0" java.lang.ArithmeticException: / by zero
     * 	at com.apple.allocation.TestThreadPool.lambda$test$0(TestThreadPool.java:37)
     * 	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
     * 	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
     * 	at java.base/java.lang.Thread.run(Thread.java:833)
     * Exception in thread "current-thread-1" java.lang.ArithmeticException: / by zero
     ...
     * Exception in thread "current-thread-2" java.lang.ArithmeticException: / by zero
     ...
     * Exception in thread "current-thread-3" java.lang.ArithmeticException: / by zero
     ...
     * Exception in thread "current-thread-4" java.lang.ArithmeticException: / by zero

     */
    @Test
    public void executeOnUnCatchException() {
        IntStream.range(0,5).forEach(value -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            threadPoolExecutor.execute(()->{
                int a= 1 / 0;
            });
        });
    }


    /**
     * 对线程执行的程序进行catch异常处理, 线程实现了复用,打印出了异常
     * 输出结果:
         current-thread-0 / by zero
         current-thread-0 / by zero
         current-thread-0 / by zero
         current-thread-0 / by zero
         current-thread-0 / by zero
     */

    @Test
    public void executeOnCatchException(){
        IntStream.range(0,5).forEach(value -> {

            try {
                Thread.sleep(1000);
            } catch (InterruptedException exception) {
                throw new RuntimeException();
            }
            threadPoolExecutor.execute(()->{
                try {
                    int a= 1 / 0;
                } catch (Exception e) {
                    System.out.println(Thread.currentThread().getName()+" "+e.getMessage());
                }
            });
        });
    }

    /**
     * 线程submit: 线程实现了复用,未抛出异常
     * 输出结果:  以下结果未简写. 只输出了 线程名报错异常没有任何输出
     * current-thread-0
     * current-thread-0
     * current-thread-0
     * current-thread-0
     * current-thread-0
     */
    @Test
    public void test2() {
        IntStream.range(0,5).forEach(value -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            threadPoolExecutor.submit(()->{
                System.out.println(Thread.currentThread().getName());
                int a= 1 / 0;
            });

        });
    }
}

二 线程池构造函数使用setUncaughtExceptionHandler构造

package com.text;


import com.google.common.util.concurrent.ThreadFactoryBuilder;
import org.junit.Test;

import java.util.concurrent.*;
import java.util.stream.IntStream;

/**
 * 设定 setUncaughtExceptionHandler
 */
/**
 *
 * 1、线程池中线程中异常尽量手动捕获
 *
 * 2、通过设置ThreadFactory的UncaughtExceptionHandler可以对未捕获的异常做保底处理,
 * 通过execute提交任务,线程依然会中断,而通过submit提交任务,可以获取线程执行结果,线程异常会在get执行结果时抛出。
 */
public class TestCatchedExceptionThreadPool {

    private ThreadPoolExecutor catchedExceptionthreadPoolExecutor = new ThreadPoolExecutor(1, 1, 20,
            TimeUnit.SECONDS, new ArrayBlockingQueue<>(100), new ThreadFactoryBuilder().setNameFormat("current-thread-%d").setUncaughtExceptionHandler(
                    (t, e) -> {
                        System.out.printf("%s ExceptionHandler 捕获了 %s%n", t.getName(), e.getMessage());
                    }
            ).build(),
            new ThreadPoolExecutor.CallerRunsPolicy());

    /**
     * 未补货的异常: 线程被回收,未抛出异常  线程对象重新new
     * 输出结果如下: 抛出异常
         current-thread-0 ExceptionHandler 捕获了 / by zero
         current-thread-1 ExceptionHandler 捕获了 / by zero
         current-thread-2 ExceptionHandler 捕获了 / by zero
         current-thread-3 ExceptionHandler 捕获了 / by zero
         current-thread-4 ExceptionHandler 捕获了 / by zero
     */
    @Test
    public void executeOnUnCatchException() {
        IntStream.range(0,5).forEach(value -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            catchedExceptionthreadPoolExecutor.execute(()->{
                int a= 1 / 0;
            });
        });
    }


    /**
     * 对线程执行的程序进行catch异常处理, 线程实现了复用,打印出了异常
     * 输出结果:  内部catch程序打印的
         current-thread-0 / by zero
         current-thread-0 / by zero
         current-thread-0 / by zero
         current-thread-0 / by zero
         current-thread-0 / by zero
     */

    @Test
    public void executeOnCatchException(){
        IntStream.range(0,5).forEach(value -> {

            try {
                Thread.sleep(1000);
            } catch (InterruptedException exception) {
                throw new RuntimeException();
            }
            catchedExceptionthreadPoolExecutor.execute(()->{
                try {
                    int a= 1 / 0;
                } catch (Exception e) {
                    System.out.println(Thread.currentThread().getName()+" "+e.getMessage());
                }
            });
        });
    }

    /**
     * 线程submit: 线程实现了复用,未抛出异常
     * 输出结果:  无任何输出,

     */
    @Test
    public void test2() {
        IntStream.range(0,5).forEach(value -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            catchedExceptionthreadPoolExecutor.submit(()->{
                int a= 1 / 0;
            });

        });
    }

    /**
     * 通过submit提交线程可以屏蔽线程中产生的异常,达到线程复用。当get()执行结果时异常才会抛出。
     *
     * 原因是通过submit提交的线程,当发生异常时,会将异常保存,待future.get();时才会抛出。
     */
    @Test
    public void test3() {
        IntStream.range(0,5).forEach(value -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            Future<?> submit = catchedExceptionthreadPoolExecutor.submit(() -> {
                int a = 1 / 0;
            });

            System.out.println("------");
            try {
                submit.get();
            } catch (Exception e) {
                System.out.println(Thread.currentThread().getName()+ e.getMessage());
            }
        });
    }
}

三 总结

1  线程出现未捕获异常的时候执行不下去会被垃圾回收

2 线程池中 execute  :    

        a)出现未捕获异常线程也会被回收无法实现复用

        b) 程序内捕获 可以实现线程复用

        c) 设置setUncaughtExceptionHandler 回线程也无法复用,只能保底

3 线程池中submit

        a)出现未捕获异常可以实现复用, 但等到Future.get() 时才会抛出异常

        b)其他与excute相同

刚看完一个月就忘了....再来看看...2023年10月13日

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值