在业务中,我们经常会碰到一些需要定时去完成的任务,例如定时的数据统计、定时发送邮件、定时获取消息等。
Spring为我们提供了强大的@Scheduled注解

注解注意点

  1. 作用于方法、注解。 也就是说可以在方法上作用,或者在其他注解上注释,这样另一个注解就有了定时任务的功能。
  2. 可以重复注释。当你描述不清需求的时候可以拆分成多个@Scheduled进行注释,但是注意当多个@Scheduled在同一时刻触发时会同时执行。
  3. 默认为单线程执行。也就是当你多个方法@Scheduled在同一时刻触发时会按顺序执行,并不会同时执行。

默认配置的简单使用(单线程)

下面使用SpringBoot项目简单介绍使用

@EnableScheduling 
// 1. 使用@EnableScheduling 启动注解 可以在启动类上也可以在执行的类上
@Component
// 2. 将该类注入Spring容器
@Slf4j
public class TestTask {@Scheduled(cron = "0/20 * * * * ?")// 3. 使用corn表达式进行执行public void test1(){try {Thread.sleep(20000);} catch (InterruptedException e) {e.printStackTrace();}log.info(Thread.currentThread().getName()+"每20秒打印一次");}@Scheduled(cron = "0/5 * * * * ?")public void test2(){log.info(Thread.currentThread().getName()+"每5秒打印一次");}
}

corn 表达式有从左到右分别表示( [秒] [分] [小时] [日] [月] [周] [年] )可以不标注年
关于corn 表达式的知识可以移步 corn表达式

以上test1()是每20秒执行一次执行时停滞20秒test2()每5秒执行一次

执行结果

在这里插入图片描述
这个结果说明了只有一个线程在执行就是scheduling-1并且线程阻塞了后续任务也只能等待。

增加配置(多线程)

由于某些任务需要同时执行,所以必须有多个线程可以同时提供。@Scheduled提供了可以配置的类 ,只要实现SchedulingConfigurer

@Configuration
public class ScheduleConfig implements SchedulingConfigurer {private volatile AtomicInteger threadFlag = new AtomicInteger(0);@Overridepublic void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {// 配置当前定时任务执行的线程为核心线程数10的执行线程scheduledTaskRegistrar.setScheduler(getScheduleThreadPool());}@Beanpublic ExecutorService getScheduleThreadPool() {return new ScheduledThreadPoolExecutor(10,scheduleThreadFactory());}@Bean // 这里根据需求重新生成命名规则public ThreadFactory scheduleThreadFactory() {return r -> {Thread t = new Thread(r);t.setName("TaskThread ---" + threadFlag.getAndIncrement());return t;};}
}

执行结果

在这里插入图片描述

在启动线程池配置之后各个任务的执行能同时执行。可以看到多个线程在争抢任务。

其他参数

String zone() default ""; // 时间的时区 默认使用getTimeZone获取
long fixedDelay() default -1; // 上次执行完毕后一定时间执行
long fixedRate() default -1; // 上次开始执行后一定时间执行
long initialDelay() default -1;// 第一次执行时多久时间后执行
// 以上三个参数默认单位都是毫秒

源码分析

在这里插入图片描述
图中,可以看到没有声明线程池时默认使用的是单线程线程池Executors.newSingleThreadScheduledExecutor();
在这里插入图片描述
这里会计算第一次执行的时间和之后执行的时间间隔,然后返回对应的任务。
所以其本质还是维护了一个可计划执行的线程池和多个不同任务的执行计划。

在这里插入图片描述

肉 肉
原创文章 35获赞 22访问量 1万+
关注私信
展开阅读全文