ThreadPoolExecutor获取原始异常
ThreadPoolExecutor作用
ThreadPoolTaskExecutor是Spring框架提供的一个线程池实现,它是基于Java的ThreadPoolExecutor实现的。ThreadPoolTaskExecutor可以管理线程池中的线程,以满足多线程并发执行任务的需要。
FutureTask作用
FutureTask的主要作用是在多线程环境下,获取异步执行的结果。在执行该任务时,可以通过Future接口的get()方法来获取任务的执行结果,而不必串行阻塞等待。由此,FutureTask可以通过异步的方式充分利用服务器资源,提高代码的执行效率与响应速度。
get方法可能会阻塞当前线程,如果任务还没有执行完成,会一直等待,直到任务执行完成后返回结果。如果不想等待任务执行完成,可以使用isDone方法判断任务是否已经执行完成。
ThreadPoolTaskExecutor配合Future使用
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;public class ThreadPoolTaskExecutorWithFutureExample {public static void main(String[] args) throws Exception {//配置ThreadPoolTaskExecutorThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(5);executor.setMaxPoolSize(10);executor.setQueueCapacity(50);executor.setThreadNamePrefix("MyThreadPool-");executor.initialize();MyTask task = new MyTask();//使用executor.submit()方法提交任务到线程池中执行,并得到Future对象。Future<Integer> future = executor.submit(task);//在需要的时候调用future.get()方法获取任务的执行结果,如果任务还没有执行完成,该方法将阻塞当前线程直到任务执行完成。int result = future.get();System.out.println("Result: " + result);executor.shutdown();}/* //创建一个实现Callable接口的任务类,该类封装了要执行的任务,并返回结果。*/static class MyTask implements Callable<Integer> {@Overridepublic Integer call() throws Exception {return 1 + 1;}}
}
ThreadPoolTaskExecutor异常处理
下面是一段会出现异常的代码:
public class ThreadPoolTaskExecutorWithFutureExample {public static void main(String[] args) {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();try {//配置ThreadPoolTaskExecutorexecutor.setCorePoolSize(5);executor.setMaxPoolSize(10);executor.setQueueCapacity(50);executor.setThreadNamePrefix("MyThreadPool-");executor.initialize();MyTask task = new MyTask();Future<Integer> future = executor.submit(task);int result = future.get();System.out.println("Result: " + result);executor.shutdown();} catch (Exception e) {System.out.println(e.getCause().getMessage());}}/* //创建一个实现Callable接口的任务类,该类封装了要执行的任务,并返回结果。*/static class MyTask implements Callable<Integer> {@Overridepublic Integer call() {//抛出异常int i = 1 / 0;return 1 + 1;}}
}
异常日志:
可以看到,控制台只是以info级别日志打印了以上异常信息。那么异常信息将会在info日志文件中记录。这样不利于错误排查,显然不符合生产环境要求!
解决方案
一:重写ThreadPoolExecutorAfterExecute
public class ThreadPoolExecutorAfterExecuteExample {public static void main(String[] args) {ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>()) {@Overrideprotected void afterExecute(Runnable r, Throwable t) {super.afterExecute(r, t);if (t == null) {System.out.println("Task " + r.toString() + " completed successfully");} else {System.out.println("Task " + r.toString() + " failed with exception: " + t.getMessage());}}};executor.execute(() -> {System.out.println("Task 1");throw new RuntimeException("Task 1 failed");});executor.execute(() -> {System.out.println("Task 2");});executor.execute(() -> {System.out.println("Task 3");throw new RuntimeException("Task 3 failed");});executor.shutdown();}
}
二:手动抛出新的异常
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();try {//配置ThreadPoolTaskExecutorexecutor.setCorePoolSize(5);//配置代码int result = future.get();System.out.println("Result: " + result);executor.shutdown();} catch (Exception e) {System.out.println(e.getCause().getMessage());//手动创建抛出异常throw new RuntimeException(e);}
}