本文内容总结自spring官方文档 spring integrates task execution and scheduling, 墙裂推荐;
本文代码,参见: github springDiscover repo 的【chapter31schedule】章节
spring框架使用 TaskExecutor 与 TaskScheduler 接口提供了对任务异步执行与调度的抽象;
1)执行器概念:执行器是JDK为线程池概念取的名字。执行器名字源于一个事实,即无法保证底层实现是一个池子。一个执行器可能是单线程甚至是同步执行的。spring的抽象隐藏了javase与Jakarta ee环境的细节。
spring的TaskExecutor接口与java.util.concurrent.Executor接口是相同的,前者继承后者。该接口有一个方法 (execute(Runnable task)
) 用于接收一个任务在线程池语义与配置下执行。
public interface TaskExecutor extends Executor {
void execute(Runnable task);
}
2)起初,TaskExecutor是为了给spring组件提供线程池抽象而创建的,如ApplicationEventMulticaster, JMS’s AbstractMessageListenerContainer,以及Quartz集成都使用TaskExecutor对池化线程进行抽象。
3)所以:简单理解,spring的任务执行器TaskExecutor,就当做 jdk的Executor来使用 ;
1)spring提供了多个TaskExecutor实现类。
2)从6.1开始,ThreadPoolTaskExecutor通过spring生命周期管理提供了暂停与恢复功能,优雅关闭功能。
【SyncTaskExecutor】同步任务执行器;
public class SyncTaskExecutor implements TaskExecutor, Serializable {
public SyncTaskExecutor() {
}
public void execute(Runnable task) {
Assert.notNull(task, "Runnable must not be null");
task.run();
}
}
【SimpleAsyncTaskExecutor】简单异步任务执行器
public class SimpleAsyncTaskExecutor extends CustomizableThreadCreator implements AsyncListenableTaskExecutor, Serializable, AutoCloseable {
public static final int UNBOUNDED_CONCURRENCY = -1;
public static final int NO_CONCURRENCY = 0;
private final ConcurrencyThrottleAdapter concurrencyThrottle = new ConcurrencyThrottleAdapter();
@Nullable
private VirtualThreadDelegate virtualThreadDelegate;
@Nullable
private ThreadFactory threadFactory;
@Nullable
private TaskDecorator taskDecorator;
private long taskTerminationTimeout;
@Nullable
private Set<Thread> activeThreads;
private volatile boolean active = true;
// ...
}
【ConcurrentTaskExecutor】内部封装了jdk的Executor
public class ConcurrentTaskExecutor implements AsyncListenableTaskExecutor, SchedulingTaskExecutor {
private static final Executor STUB_EXECUTOR = (task) -> {
throw new IllegalStateException("Executor not configured");
};
@Nullable
private static Class<?> managedExecutorServiceClass;
private Executor concurrentExecutor; // 内部封装了jdk的Executor
private TaskExecutorAdapter adaptedExecutor;
@Nullable
private TaskDecorator taskDecorator;
public ConcurrentTaskExecutor(@Nullable Executor executor) {
this.concurrentExecutor = STUB_EXECUTOR;
this.adaptedExecutor = new TaskExecutorAdapter(STUB_EXECUTOR);
if (executor != null) {
this.setConcurrentExecutor(executor);
}
}
// ......
}
【ThreadPoolTaskExecutor】线程池任务执行器, 封装了ThreadPoolExecutor
public class ThreadPoolTaskExecutor extends ExecutorConfigurationSupport implements AsyncListenableTaskExecutor, SchedulingTaskExecutor {
private final Object poolSizeMonitor = new Object();
private int corePoolSize = 1;
private int maxPoolSize = Integer.MAX_VALUE;
private int keepAliveSeconds = 60;
private int queueCapacity = Integer.MAX_VALUE;
private boolean allowCoreThreadTimeOut = false;
private boolean prestartAllCoreThreads = false;
private boolean strictEarlyShutdown = false;
@Nullable
private TaskDecorator taskDecorator;
@Nullable
private ThreadPoolExecutor threadPoolExecutor;
private final Map<Runnable, Object> decoratedTaskMap;
public ThreadPoolTaskExecutor() {
this.decoratedTaskMap = new ConcurrentReferenceHashMap(16, ReferenceType.WEAK);
}
// ......
}
【SchedulingTaskExecutor】调度任务执行器
public interface SchedulingTaskExecutor extends AsyncTaskExecutor {
default boolean prefersShortLivedTasks() {
return true;
}
}
【AsyncTaskExecutor】异步任务执行器,继承自 TaskExecutor
public interface AsyncTaskExecutor extends TaskExecutor {
// ......
default Future<?> submit(Runnable task) {
FutureTask<Object> future = new FutureTask(task, (Object)null);
this.execute(future);
return future;
}
default <T> Future<T> submit(Callable<T> task) {
FutureTask<T> future = new FutureTask(task);
this.execute(future, Long.MAX_VALUE);
return future;
}
default CompletableFuture<Void> submitCompletable(Runnable task) {
return CompletableFuture.runAsync(task, this);
}
default <T> CompletableFuture<T> submitCompletable(Callable<T> task) {
return FutureUtils.callAsync(task, this);
}
}
【小结】任务执行器的类层次关系:(TaskExecutor继承jdk的Executor)
【TaskExecutorExample】业务场景:异步打印消息
public class TaskExecutorExample {
private class MessagePrinterTask implements Runnable {
private String message;
public MessagePrinterTask(String message) {
this.message = message;
}
public void run() {
System.out.println("线程id=" + Thread.currentThread().getId() + ", message=" + message);
try {
TimeUnit.MILLISECONDS.sleep(200);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
private TaskExecutor taskExecutor;
public TaskExecutorExample(TaskExecutor taskExecutor) {
this.taskExecutor = taskExecutor;
}
public void printMessages() {
for(int i = 0; i < 25; i++) {
taskExecutor.execute(new MessagePrinterTask("Message" + i));
}
}
// main函数: 案例执行入口
public static void main(String[] args) {
ThreadPoolTaskExecutor threadPoolTaskExecutor = buildThreadPoolTaskExecutor();
new TaskExecutorExample(threadPoolTaskExecutor).printMessages();
threadPoolTaskExecutor.shutdown();
}
private static ThreadPoolTaskExecutor buildThreadPoolTaskExecutor() {
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
// 设置属性前,必须先调用initialize()初始化Executor,实际底层调用 ThreadPoolTaskExecutor#initializeExecutor()
threadPoolTaskExecutor.initialize();
threadPoolTaskExecutor.setWaitForTasksToCompleteOnShutdown(true); // 等待任务执行完成后再关闭执行器
threadPoolTaskExecutor.setCorePoolSize(2);
threadPoolTaskExecutor.setMaxPoolSize(3);
threadPoolTaskExecutor.setKeepAliveSeconds(0);
threadPoolTaskExecutor.setQueueCapacity(100);
return threadPoolTaskExecutor;
}
}
【执行效果】
线程id=15, message=Message0
线程id=16, message=Message1
线程id=16, message=Message2
线程id=15, message=Message3
线程id=16, message=Message5
线程id=15, message=Message4
线程id=16, message=Message6
线程id=15, message=Message7
线程id=16, message=Message8
线程id=15, message=Message9
线程id=16, message=Message10
线程id=15, message=Message11
线程id=16, message=Message12
线程id=15, message=Message13
线程id=15, message=Message14
线程id=16, message=Message15
线程id=15, message=Message16
线程id=16, message=Message17
线程id=15, message=Message18
线程id=16, message=Message19
线程id=15, message=Message20
线程id=16, message=Message21
线程id=15, message=Message22
线程id=16, message=Message23
线程id=15, message=Message24
【代码解说】
1)spring有一个TaskScheduler接口,定义了很多方法用于调度任务在未来某个时间点执行;
public interface TaskScheduler {
default Clock getClock() {
return Clock.systemDefaultZone();
}
ScheduledFuture<?> schedule(Runnable task,