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");
}
执行结果,可以看到异步执行的异常不会影响主线程的执行。
二、解决办法
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");
}
执行结果如下,已经拿到了执行异常
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);
}
异常都已经处理到。
本作品采用《CC 协议》,转载必须注明作者和本文链接