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 {
//配置ThreadPoolTaskExecutor
ThreadPoolTaskExecutor 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> {
@Override
public Integer call() throws Exception {
return 1 + 1;
}
}
}
ThreadPoolTaskExecutor异常处理
下面是一段会出现异常的代码:
public class ThreadPoolTaskExecutorWithFutureExample {
public static void main(String[] args) {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
try {
//配置ThreadPoolTaskExecutor
executor.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> {
@Override
public 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<>()) {
@Override
protected 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 {
//配置ThreadPoolTaskExecutor
executor.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);
}
}