SpringBoot中的定时任务的同步与异步你确定真的知道?

定时任务调度功能在我们的开发中是非常常见的,随便举几个例子:定时清除一些过期的数据,定时发送邮件等等,实现定时任务调度的方式也十分多样,本篇文章主要学习各种实现定时任务调度方式的优缺点,以便为日后选择的时候提供一定的参考 。
本篇要点

  • 介绍Timer实现定时任务 。
  • 介绍ScheduledExecutorService实现定时任务 。
  • 介绍SpringBoot使用SpringTask实现定时任务 。
  • 介绍SpringBoot使用SpringTask实现异步任务 。
Timer实现定时任务基于JDK自带的JAVA.util.Timer,通过调度java.util.TimeTask让某一段程序按某一固定间隔,在某一延时之后定时执行 。
缺点:
  1. 无法指定某一时间的时候执行 。
  2. 存在潜在bug,Timer运行多个TimeTask时,只要其中之一没有捕获抛出的异常,其它任务便会自动终止运行 。
public class DemoTimer {//延时时间private static final long DELAY = 3000;//间隔时间private static final long PERIOD = 5000;public static void main(String[] args) {// 定义要执行的任务TimerTask task = new TimerTask() {@Overridepublic void run() {System.out.println("任务执行 --> " + LocalDateTime.now());}};Timer timer = new Timer();timer.schedule(task, DELAY, PERIOD);}}ScheduledExecutorService实现定时任务阿里巴巴开发规范明确规定:希望开发者使用ScheduledExecutorService代替Timer 。
多线程并行处理定时任务时,Timer运行多个TimeTask时,只要其中之一没有捕获抛出的异常,其它任务便会自动终止运行,使用ScheduledExecutorService则没有这个问题 。
public class DemoScheduledExecutorService {//延时时间private static final long DELAY = 3000;//间隔时间private static final long PERIOD = 5000;public static void main(String[] args) {Runnable task = new Runnable() {@Overridepublic void run() {System.out.println("任务执行 --> " + LocalDateTime.now());}};ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();service.scheduleAtFixedRate(task, DELAY, PERIOD, TimeUnit.MILLISECONDS);}}SpringBoot使用Spring Task实现定时任务自动配置实现原理Spring为我们提供了异步执行任务调度的方式,提供TaskExecutor,TaskScheduler接口,而SpringBoot的自动配置类org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration为我们默认注入了他们的实现:ThreadPoolTaskScheduler,本质上是ScheduledExecutorService 的封装,增强在调度时间上的功能 。
SpringBoot中的定时任务的同步与异步你确定真的知道?

文章插图
 
@ConditionalOnClass(ThreadPoolTaskScheduler.class)@Configuration(proxyBeanMethods = false)@EnableConfigurationProperties(TaskSchedulingProperties.class)@AutoConfigureAfter(TaskExecutionAutoConfiguration.class)public class TaskSchedulingAutoConfiguration { @Bean @ConditionalOnBean(name = TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME) @ConditionalOnMissingBean({ SchedulingConfigurer.class, TaskScheduler.class, ScheduledExecutorService.class }) public ThreadPoolTaskScheduler taskScheduler(TaskSchedulerBuilder builder) {return builder.build(); } @Bean @ConditionalOnMissingBean public TaskSchedulerBuilder taskSchedulerBuilder(TaskSchedulingProperties properties,ObjectProvider<TaskSchedulerCustomizer> taskSchedulerCustomizers) {TaskSchedulerBuilder builder = new TaskSchedulerBuilder();builder = builder.poolSize(properties.getPool().getSize());Shutdown shutdown = properties.getShutdown();builder = builder.awaitTermination(shutdown.isAwaitTermination());builder = builder.awaitTerminationPeriod(shutdown.getAwaitTerminationPeriod());builder = builder.threadNamePrefix(properties.getThreadNamePrefix());builder = builder.customizers(taskSchedulerCustomizers);return builder; }}新建工程,引入依赖Spring Task是Spring Framework中的模块,我们只需引入spring-boot-starter依赖就可以了 。
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency>编写配置类@EnableScheduling@Configuration@EnableSchedulingpublic class ScheduleConfig {}
  • @Configuration表明这是个配置类 。
  • @EnableScheduling表明启用Spring的定时任务调度功能 。
定义定时任务@Scheduled@Component@Slf4jpublic class DemoTask {private final AtomicInteger counts = new AtomicInteger();@Scheduled(cron = "0/5 * * * * *")public void execute() {log.info("[定时任务第 {} 次执行]", counts.incrementAndGet());}}