@schedule

@schedule注解参数有如下

       * cron:cron表达式,指定任务在特定时间执行;
       * fixedDelay:表示上一次任务执行完成后多久再次执行,参数类型为long,单位ms;
       * fixedDelayString:与fixedDelay含义一样,只是参数类型变为String;
       * fixedRate:表示按一定的频率执行任务,参数类型为long,单位ms;
       * fixedRateString: 与fixedRate的含义一样,只是将参数类型变为String;
       * initialDelay:表示延迟多久再第一次执行任务,参数类型为long,单位ms;
       * initialDelayString:与initialDelay的含义一样,只是将参数类型变为String;

Delay的Rate区别在于Delay是任务完成之后多久执行, Rate是任务开始之后多久执行,一个是按完成时间计时 一个是按开始时间计时

@schedule原理

@schedule底层使用的是spring的任务调度线程池ThreadPoolTaskScheduler,ThreadPoolTaskScheduler底层使用的为JDK自带的ScheduledExecutorService(其实现类为ScheduledThreadPoolExecutor)

关于ScheduledThreadPoolExecutor(ScheduledExecutorService的实现)源码推荐文章https://www.jianshu/p/a39a89d28375,https://www.jianshu/p/8c4c160ebdf7这边就不在详细说明了 只做简单的说明

第一步 将任务添加到线程池的任务队列中

           此处知识点: 1 线程池:ScheduledThreadPoolExecutor 继承 ThreadPoolExecutor所以此处线程池为                                                                   ThreadPoolExecutor

                                  2 任务队列:此处任务队列为ThreadPoolExecutor中的一个无界延时阻塞队列(JDK队列推荐文章                                                     https://www.zybuluo/mikumikulch/note/712598)

第二步 线程池中的线程获取到延时队列中的任务第一次执行

第三步 延时队列中任务被线程执行完毕之后,重新根据我们传入的时间频率设置这个任务的时间放入到延时队列中,以此达到                任务被周期性反复的一直调用

因为任务执行完之后才被放入到队列中再次选取线程执行  所以定时任务线程池中不管有多少线程,只有一个线程执行这个任务,这个任务结束之后,也会重新选取一个线程再次执行

注意:在spring中的@schedule默认的线程池中只有一个线程,所以如果在多个方法上加上@schedule的话,此时就会有多个任务加入到延时队列中,因为只有一个线程,所以任务只能被一个一个的执行

在使用时我们可以按需配置定时任务线程池线程的大小,这个就改变了线程数量默认为1的线程池

@Bean("threadPoolTaskScheduler")
    public ThreadPoolTaskScheduler threadPoolTaskScheduler(){
        ThreadPoolTaskScheduler executor = new ThreadPoolTaskScheduler();
        executor.setThreadNamePrefix("threadPoolTaskScheduler-");
        executor.setPoolSize(20);
        //设置线程池关闭的时候等待所有任务都完成再继续销毁其他的Bean
        executor.setWaitForTasksToCompleteOnShutdown(true);
        //设置线程池中任务的等待时间,如果超过这个时候还没有销毁就强制销毁,以确保应用最后能够被关闭,而不是阻塞住
        executor.setAwaitTerminationSeconds(60);
        //这里采用了CallerRunsPolicy策略,当线程池没有处理能力的时候,该策略会直接在 execute 方法的调用线程中运行被拒绝的任务;如果执行程序已关闭,则会丢弃该任务
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return executor;
    }

@Async

此注解会将这个任务放入到一个异步线程中执行,不会阻塞主线程,可以用在一些比较耗时并且不用考虑返回值的一些操作中

比如有一个任务是3秒执行一次,一次任务执行需要8秒,若是吧这个任务加上@Async则这个任务就会放入到异步线程中去,

则这个任务不管这个任务执行的8秒还是依然会3秒执行一次,只是每次执行的结果需要8秒钟的延迟,但是结果我们一般是不考虑的

总结

① 默认@schedule  线程池默认只有一个线程,多个任务时串行   串行

@ 配置ThreadPoolTaskScheduler的@schedule 指定线程池中线程数量,多个任务并行  并行

@ 默认@schedule + @Aysnc 多个任务之间串行,单个任务非阻塞异步执行    串行+异步

@ 配置ThreadPoolTaskScheduler的@schedule+@Async  多个任务之间并行,单个任务非阻塞异步执行    并行+异步

更多推荐

springboot @schedule和@Async定时任务的异步 同步 多任务并发