在做项目过程中,一些耗时长的任务可能需要在后台线程池中运行;典型的如发送邮件等,由于需要调用外部的接口来进行实际的发送操作,如果客户端在提交发送请求后一直等待服务器端发送成功后再返回,就会长时间的占用服务器的一个连接;当这类请求过多时,服务器连接数会不够用,新的连接请求可能无法得到满足,从而导致客户端连接失败。因此这类服务一般需要使用到后台线程池来处理。
在这种情况下,我们可以直接使用concurrent包中的线程池来处理,也可以使用其它的方案如Quartz等组件中的线程池来解决;为适配这些不同的方案,Spring引入了TaskExecutor接口作为顶层接口,并提供了几种不同的实现来满足不同的场景。
本文目录:
1 常见实现
Spring包含了以下TaskExecutor的实现:
- ThreadPoolTaskExecutor
它是最经常使用的一个,提供了一些Bean属性用于配置java.util.concurrent.ThreadPoolExecutor并且将其包装到TaskExecutor对象中。如果需要适配java.util.concurrent.Executor,请使用ConcurrentTaskExecutor。 - SimpleAsyncTaskExecutor
线程不会重用,每次调用时都会重新启动一个新的线程;但它有一个最大同时执行的线程数的限制; - SyncTaskExecutor
同步的执行任务,任务的执行是在主线程中,不会启动新的线程来执行提交的任务。主要使用在没有必要使用多线程的情况,如较为简单的测试用例。 - ConcurrentTaskExecutor
它用于适配java.util.concurrent.Executor, 一般情况下请使用ThreadPoolTaskExecutor,如果hreadPoolTaskExecutor不够灵活时可以考虑采用ConcurrentTaskExecutor。 - SimpleThreadPoolTaskExecutor
它是Quartz中SimpleThreadPool的一个实现,用于监听Spring生命周期回调事件。它主要使用在需要一个线程池来被Quartz和非Quartz中的对象同时共享使用的情况。 - WorkManagerTaskExecutor
它实现了CommonJ中的WorkManager接口,是在Spring中使用CommonJ的WorkManager时的核心类。
2 使用示例
2.1 注册TaskExecutor
此处通过spring Boot工程进行演示;在配置类中注册Bean:
@Configuration
public class MainConfiguration {
@Bean
public TaskExecutor getTaskExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setMaxPoolSize(10);
taskExecutor.setCorePoolSize(5);
taskExecutor.setQueueCapacity(20);
return taskExecutor;
}
}
此时TaskExecutor对象已经被注入Spring中,接下来就可以通过Autowired来使用。
2.2 使用TaskExecutor
使用示例较为简单,直接在一个Controller中来使用TaskExecutor提交一个测试的任务;通过打印日志来分析其执行过