Spring任务调度核心概念模型

关于任务调度,Spring 有如下几个核心概念 :

  • Task – 任务
    • 用于表示一个有待执行的任务;
    • 该任务有可能需要被执行一次;
      • 在特定的时间点执行一次;
      • 或者在某个时间点之后再延时特定的时间段之后执行一次;
    • 也有可能需要被反复执行多次;
      • 在特定时间点之后间隔特定的时间段重复执行;
      • 或者在 cron 表达式指定的运行时机重复执行;
    • Spring不存在针对任务对应的接口/类抽象,Spring中一个任务具体以一个Runnable 接口实现类对象的方式存在;
  • TaskExecutor – 任务执行器
    • 表示执行任务(Task)的线程或者线程池;
    • 并不要求一定是线程池,可以是单个线程;
    • 并不要求一定是异步执行任务,也可以是同步执行任务。对应的,有接口AsyncTaskExecutor(及其子接口 SchedulingTaskExecutor 等)、实现类SyncTaskExecutor;
    • Spring存在一个接口TaskExecutor用于抽象该任务执行器概念;
    • Spring提供若干个内置TaskExecutor实现类,常见的如下 :
      • SyncTaskExecutor – 在调用者线程内同步执行任务;
      • SimpleAsyncTaskExecutor – 不重用线程,新建线程执行任务,实现了AsyncTaskExecutor接口;
      • ThreadPoolTaskExecutor – 最常用的基于线程池的任务执行器,实现了AsyncTaskExecutor、SchedulingTaskExecutor接口。其内部借助JDK的ThreadPoolExcutor实现;
  • TaskScheduler – 任务执行调度器
    • 调度任务执行的工具

    • Spring中存在接口TaskScheduler抽象建模该概念

    • 能够按以下几种方式调度任务的执行

      • 在特定的时间点执行一次
        • ScheduledFuture schedule(Runnable task, <指定时间点>)
      • 以固定频率重复执行
        • ScheduledFuture scheduleAtFixedRate(Runnable task, <指定时间周期>)
        • ScheduledFuture scheduleAtFixedRate(Runnable task, <指定在该时间点之后重复执行> ,<指定时间周期>)
      • 延时执行一次
        • ScheduledFuture scheduleWithFixedDelay(Runnable task, <指定延时时间段>)
        • ScheduledFuture scheduleWithFixedDelay(Runnable task, <指定从该时间点之后开始延时> ,<指定延时时间段>)
      • 使用 Trigger 任务执行触发器 – 可定制,最灵活的一种任务执行触发机制;
        • ScheduledFuture schedule(Runnable task, Trigger trigger)
        • Spring提供Trigger接口用于建模任务触发器这一概念
        • Spring内置提供的 Trigger实现有 :
          • CronTrigger – 基于cron表达式的任务执行触发器
          • PeriodicTrigger – 创建延时执行一次或者固定周期执行多次的任务触发器
    • ScheduledFuture – 被调度了的任务执行

      • Spring使用ScheduledFuture接口抽象表示概念"被调度了的任务",该任务会在将来某个时刻被执行;
      • Spring通过ScheduledFuture接口可以取消调度了的任务或者检查该任务执行是否已经完成;
    • 在Spring中的默认实现是 ThreadPoolTaskScheduler,其是对jdk ScheduledExecutorService 的包装。
    • 参考资料

 

与Java自身的任务概念的一些关系:TaskExcutor接口 继承自 java.util.concurrent.Excutor 接口,ThreadPoolTaskExcutor、ThreadPoolExcutor分别是两者的一个实现。

在Spring中,使能异步能力(在main方法加 @EnableAsync )后,通过在方法上加  @Aync  即可达到让方法异步执行的目的。

原理:Spring将会为该方法创建切面,在执行到切面时将目标方法包装成一个任务,确定要用到的AsyncTaskExecutor执行并将任务提交给其执行(见 AsyncExecutionInterceptor#invoke 方法)。因此,异步执行的效果取决于执行该任务的AsyncTaskExecutor。

容器中可能有多个用于执行该任务的AsyncTaskExecutor:用户自定义并注册到容器中的,或者框架的默认者 SimpleAsyncTaskExecutor 。后者很低效,每来个任务都创建新线程执行(见其 doExecute 方法),故项目中最好要自定义AsyncTaskExecutor,且为不同的业务任务集定义各自的TaskExcutor。自定义的示例:

@Configuration
public class AsyncTaskExcutorConfig implements AsyncConfigurer {

    public static final String CUSTOM_TASK_EXECUTOR = "threadPoolTaskExecutor";

    @Override
    @Bean(value = CUSTOM_TASK_EXECUTOR)
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        taskExecutor.setCorePoolSize(10);
        taskExecutor.setMaxPoolSize(30);
        taskExecutor.setQueueCapacity(10240);
        taskExecutor.setKeepAliveSeconds(180);
        taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        taskExecutor.setThreadNamePrefix("ss-async-thread-");
        taskExecutor.initialize();
        return taskExecutor;
    }
}
View Code

可通过 @Async 的value属性指定名字来指定要用来执行该方法的AsyncTaskExcutor。在切面执行时将会优先根据名字来查对应的执行器,若找不到则用默认的执行器 SimpleAsyncTaskExecutor (见 AsyncExecutionInterceptor#determineAsyncExecutor 和 #getDefaultExecutor 方法)。可见,最好使用自定义的执行器,不然默认者效率低。

在Spring中,任务调度的原理与上面类似, @EnableScheduling @Scheduled  。

 

posted @ 2020-09-20 16:54  March On  阅读(378)  评论(0)    收藏  举报
top last
Welcome user from
(since 2020.6.1)