springBoot已经默认集成了定时任务的依赖,只须要引入基本的依赖就可使用定时任务。java
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-parent</artifactId> <version>2.0.0.RELEASE</version> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> </dependencies>
在启动类中须要加入@EnableScheduling注解,意思是开启定时任务。spring
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.scheduling.annotation.EnableScheduling; /** * Author: YaoQi * Date: 2018/9/28 21:37 * Description: springBoot schedule */ @SpringBootApplication @EnableScheduling public class ScheduleApp { public static void main(String[] args) { SpringApplication.run(ScheduleApp.class, args); } }
写一个定时任务demo,每秒种打印一第二天志,并打印当前时间验证当前任务执行周期。多线程
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; /** * Author: YaoQi * Date: 2018/9/28 21:40 * Description: Scheduled Task */ @Service public class ScheduleTask { private static final Logger logger = LoggerFactory.getLogger(ScheduleTask.class); @Scheduled(cron = "*/1 * * * * ?") public void execute() { logger.info("print word."); logger.info(String.valueOf(System.currentTimeMillis())); } }
运行结果:ide
从上图的结果中看:该任务基本是每秒种执行一次,若是不手动中止,程序会一直执行下去,而且从日志中看,这个任务的执行周期是1s左右,恰好和设置的cron表达式一致;而且执行这个任务的线程一直是poll-1-thread-1这个线程。这就意味着,这个定时任务启动是由单独的一个线程去执行的。spring-boot
这时候,可能会有几个问题:ui
若是任务执行的时间比执行周期要短,这个任务会怎么执行?线程
若是有多个任务执行,还会是一个线程去执行这个任务吗?日志
首先验证第一个问题,当任务执行的时间比执行周期短时,任务的执行状况。code
@Scheduled(cron = "*/1 * * * * ?") public void execute() { logger.info("print word."); logger.info(String.valueOf(System.currentTimeMillis())); try { Thread.sleep(6000L); } catch (InterruptedException e) { e.printStackTrace(); } }
执行结果:每次任务的执行时间间隔为7秒,而且是同一个线程在执行。xml
若是有多个任务执行,任务的执行状况。
@Scheduled(cron = "*/1 * * * * ?") public void execute() { logger.info("print word."); try { Thread.sleep(6000L); } catch (InterruptedException e) { e.printStackTrace(); } } @Scheduled(cron = "*/1 * * * * ?") public void execute1() { logger.info(String.valueOf(System.currentTimeMillis())); logger.info("write message."); }
执行结果:
执行结果:第二个每秒执行一次的任务的并无安装设定的执行周期执行,运行结果并无达到预期。而且两个任务都是由同一个线程去运行。
示例分析中问题2的缘由就是执行多个任务并非多个线程执行,致使执行第一个任务时,第二个任务进入等待状态。springBoot中提供了多线程运行定时任务的方式。
@Configuration public class ScheduleConfig implements SchedulingConfigurer { @Override public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { taskRegistrar.setScheduler(Executors.newScheduledThreadPool(3)); } }
增长一个配置类,设置线程池,并设置线程池大小,这里的线程池大小就仁者见仁了,和你程序中的任务的个数有关系,也和机器的核数有关系。
经过配置线程池就能让每一个任务独立执行,不受其余任务的影响,由于是在不一样的线程中执行的,但若是涉及到公共资源就另当别论了。
执行结果:
上述中的执行周期都是以cron表达式定义的,这种方式最灵活,可是上文中的表达式都写到代码中去了,不便于修改,这里提供一种配置方式,直接用表达式获取yml中的配置信息。
scheduleTask: cron1: "*/1 * * * * ?" cron2: "*/1 * * * * ?"
在yml中添加cron的配置信息。而后在Java注解中能够直接获取。
@Scheduled(cron = "${scheduleTask.cron2}") public void execute1() { logger.info(String.valueOf(System.currentTimeMillis())); logger.info("write message."); }