在做项目过程中,一些耗时长的任务可能需要在后台线程池中运行;典型的如发送邮件等,由于需要调用外部的接口来进行实际的发送操作,如果客户端在提交发送请求后一直等待服务器端发送成功后再返回,就会长时间的占用服务器的一个连接;当这类请求过多时,服务器连接数会不够用,新的连接请求可能无法得到满足,从而导致客户端连接失败。因此这类服务一般需要使用到后台线程池来处理。 在这种情况下,我们可以直接使用concurrent包中的线程池来处理,也可以使用其它的方案如Quartz等组件中的线程池来解决;为适配这些不同的方案,Spring引入了TaskExecutor接口作为顶层接口,并提供了几种不同的实现来满足不同的场景。
一、TaskExecutor常见实现类
(1)ThreadPoolTaskExecutor
它是最经常使用的一个,提供了一些Bean属性用于配置java.util.concurrent.ThreadPoolExecutor并且将其包装到TaskExecutor对象中。如果需要适配java.util.concurrent.Executor,请使用ConcurrentTaskExecutor。
(2)SimpleAsyncTaskExecutor
线程不会重用,每次调用时都会重新启动一个新的线程;但它有一个最大同时执行的线程数的限制;支持并发,超过最大并发调用数时,会阻塞,直到释放一个槽为止。
(3)SyncTaskExecutor
同步的执行任务,任务的执行是在主线程中,不会启动新的线程来执行提交的任务。主要使用在没有必要使用多线程的情况,如较为简单的测试用例。
(4)ConcurrentTaskExecutor
它用于适配java.util.concurrent.Executor, 一般情况下请使用ThreadPoolTaskExecutor,如果hreadPoolTaskExecutor不够灵活时可以考虑采用ConcurrentTaskExecutor。
(5)SimpleThreadPoolTaskExecutor
它是Quartz中SimpleThreadPool的一个实现,用于监听Spring生命周期回调事件。它主要使用在需要一个线程池来被Quartz和非Quartz中的对象同时共享使用的情况。
(6)WorkManagerTaskExecutor
使用CommonJ WorkManager作为它的支持实现,并且是在Spring上下文中设置CommonJ WorkManager引用的中心便利类。与SimpleThreadPoolTaskExecutor类似,这个类实现了WorkManager接口,因此也可以直接作为WorkManager使用。
二、使用TaskExecutor实例
/**
* 测试TaskExecutor
*/
public class TaskExecutorExample {
/**
* 创建一个线程类,该类主要用于打印信息功能
*/
private class MessagePrinterTask implements Runnable {
private String message;
public MessagePrinterTask(String message) {
this.message = message;
}
@Override
public void run() {
System.out.println(message);
}
}
private TaskExecutor taskExecutor;
// 构造器 实例化TaskExecutorExample类需要TaskExecutor实例
public TaskExecutorExample(TaskExecutor taskExecutor) {
this.taskExecutor = taskExecutor;
}
public void printMessages() {
for (int i = 0; i < 25; i++) {
// 执行任务
taskExecutor.execute(new MessagePrinterTask("Message:" + i));
}
}
}
<bean id="taskExecutor"
class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<!-- 核心线程数 -->
<property name="corePoolSize" value="5" />
<!-- 最大线程数 -->
<property name="maxPoolSize" value="10" />
<!-- 队列容量 -->
<property name="queueCapacity" value="25" />
</bean>
<bean id="taskExecutorExample"
class="com.buba.task.TaskExecutorExample"
init-method="printMessages">
<!-- 构造器注入 -->
<constructor-arg ref="taskExecutor" />
</bean>