SpringBoot 线程池异常处理

一、问题

由于异步是独立线程执行,那如果异步执行过程出现了异常,调用者是不会知道的,如何进行异常处理就成了个问题。

1.1代码验证

@Async("taskExecutor")
@Override
public void syncFileWithException() {
    log.info("syncFileWithException,current thread is {}",Thread.currentThread().getName());
    System.out.println(10/0);
    log.info("ArithmeticException");
}

测试

@Test
public void syncFileWithException() throws InterruptedException {
    threadPoolService.syncFileWithException();
    Thread.sleep(300);
    log.info("end");
}

执行结果,可以看到异步执行的异常不会影响主线程的执行。

SpringBoot 线程池异常处理

二、解决办法

2.1、有返回值的异常处理

在执行返回了Future的方法时,可以直接捕获返回结果的get方法的异常,然后进行处理

@Async("taskExecutor")
@Override
public Future<Result> syncFileWithExceptionResult() {
    log.info("syncFileWithExceptionResult,current thread is {}",Thread.currentThread().getName());
    throw new NullPointerException();
}

测试

@Test
public void syncFileWithExceptionResult() {
    Future<Result> resultFuture = threadPoolService.syncFileWithExceptionResult();
    try {
        Result result = resultFuture.get();
    } catch (InterruptedException e) {
        log.error("InterruptedException: {}",e);
    } catch (ExecutionException e) {
        log.error("ExecutionException: {}",e);
    }
    log.info("syncFileWithExceptionResult done");
}

执行结果如下,已经拿到了执行异常

SpringBoot 线程池异常处理

2.2、无返回值的异常处理

无返回值的方法,可以使用AsyncConfigurer接口配置线程池和统一异常处理逻辑,异步接口配置如下

@Configuration
@EnableAsync
@Slf4j
public class ThreadPoolConfig implements AsyncConfigurer {


    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        int availableProcessors = Runtime.getRuntime().availableProcessors();
        executor.setCorePoolSize(availableProcessors);
        executor.setMaxPoolSize(maxPoolSize);
        executor.setQueueCapacity(queueCapacity);
        executor.setKeepAliveSeconds(keepAliveSeconds);
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.setThreadNamePrefix(threadNamePrefix);
        executor.setWaitForTasksToCompleteOnShutdown(waitForTasksToCompleteOnShutdown);
        executor.initialize();
        return executor;
    }

    /**
     * 适用于无返回值的异常处理
     * 统一异常获取和处理逻辑
     */
    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return (ex, method, params) -> {
            log.info("error method: {}",method.getName());
            for (Object param : params) {
                log.info("method param: {}",param);
            }
            log.info("exception: {}",ex);
        };
    }
}

业务代码

@Async("taskExecutor")
    @Override
    public void syncFileWithException() {
        log.info("syncFileWithException,current thread is {}",Thread.currentThread().getName());
        throw new NullPointerException();
    }

    @Async("taskExecutor")
    @Override
    public void syncFileWithException(int a) {
        log.info("syncFileWithException,current thread is {}",Thread.currentThread().getName());
        throw new NullPointerException();
    }

    @Async("taskExecutor")
    @Override
    public void syncFileWithException(int a, int b) {
        log.info("syncFileWithException,current thread is {}",Thread.currentThread().getName());
        throw new NullPointerException();
    }

测试

@Test
public void syncFileWithExceptionTest() {
    threadPoolService.syncFileWithException();
    threadPoolService.syncFileWithException(100);
    threadPoolService.syncFileWithException(1,99);
}

异常都已经处理到。

SpringBoot 线程池异常处理

本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!