SpringBoot之定时任务详解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhou_fan_xi/article/details/87874838

一、静态:基于注解

基于注解@Scheduled默认为单线程,开启多个任务时,任务的执行时机会受上一个任务执行时间的影响。

1、创建定时器

@Configuration
@EnableScheduling //开启定时任务
public class ScheduleTask {
    @Scheduled(cron = "0/5 * * * * ?")
    //或直接指定时间间隔,例如:5秒
    //@Scheduled(fixedRate=5000)
    public void task(){
        System.out.println("执行静态定时任务"+Thread.currentThread().getName()+"时间"+LocalDateTime.now());
    }
}

Cron表达式参数分别表示:

  • 秒(0~59) 例如0/5表示每5秒
  • 分(0~59)
  • 时(0~23)
  • 日(0~31)的某天,需计算
  • 月(0~11)
  • 周几( 可填1-7 或 SUN/MON/TUE/WED/THU/FRI/SAT)

@Scheduled:除了支持灵活的参数表达式cron之外,还支持简单的延时操作,例如 fixedDelay ,fixedRate 填写相应的毫秒数即可。

启动应用,可以看到控制台打印出如下信息:

执行静态定时任务pool-10-thread-1时间2019-02-22T11:15:35.001
执行静态定时任务pool-10-thread-1时间2019-02-22T11:15:40.001
执行静态定时任务pool-10-thread-1时间2019-02-22T11:15:45
执行静态定时任务pool-10-thread-1时间2019-02-22T11:15:50.001
执行静态定时任务pool-10-thread-1时间2019-02-22T11:15:55
执行静态定时任务pool-10-thread-1时间2019-02-22T11:16:00.001
执行静态定时任务pool-10-thread-1时间2019-02-22T11:16:05.001

 显然,使用@Scheduled 注解很方便,但缺点是当我们调整了执行周期的时候,需要重启应用才能生效,这多少有些不方便。为了达到实时生效的效果,可以使用接口来完成定时任务。

二、动态:基于接口

基于接口(SchedulingConfigurer)

1、导入依赖包:

 <parent>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter</artifactId>
 <version>2.0.4.RELEASE</version>
 </parent>
 <dependencies>
 <dependency><!--添加Web依赖 -->
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-web</artifactId>
 </dependency>
 <dependency><!--添加MySql依赖 -->
 <groupId>mysql</groupId>
 <artifactId>mysql-connector-java</artifactId>
 </dependency>
 <dependency><!--添加Mybatis依赖 配置mybatis的一些初始化的东西-->
 <groupId>org.mybatis.spring.boot</groupId>
 <artifactId>mybatis-spring-boot-starter</artifactId>
 <version>1.3.1</version>
 </dependency>
 <dependency><!-- 添加mybatis依赖 -->
 <groupId>org.mybatis</groupId>
 <artifactId>mybatis</artifactId>
 <version>3.4.5</version>
 <scope>compile</scope>
 </dependency>
 </dependencies>

2、添加数据库记录:

3、创建定时器

数据库准备好数据之后,我们编写定时任务,注意这里添加的是TriggerTask,目的是循环读取我们在数据库设置好的执行周期,以及执行相关定时任务的内容。

@SuppressWarnings("ALL")
@Configuration
@EnableScheduling
public class DynamicScheduleTask implements SchedulingConfigurer {

    @Autowired //注入mapper
    getCronMapper cronMapper;

    @Override
    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
        scheduledTaskRegistrar.addTriggerTask(
                //添加任务内容
                () -> System.out.println("执行动态定时任务"+ LocalDateTime.now().toLocalTime()),
                //设置执行周期
                triggerContext -> {
                    //从数据库获取执行周期
                    String cron = cronMapper.getCron();
                    //合法性校验
                    if(StringUtils.isBlank(cron)){

                    }
                    return new CronTrigger(cron).nextExecutionTime(triggerContext);
                }
        );
    }
}
public interface getCronMapper{
        @Select("SELECT cron FROM cron")
        String getCron();
    }

启动应用后,查看控制台,打印时间是我们预期的每5秒一次

然后打开Navicat ,将执行周期修改为每6秒执行一次

查看控制台,发现执行周期已经改变,并且不需要我们重启应用,十分方便。

注意: 如果在数据库修改时格式出现错误,则定时任务会停止,即使重新修改正确;此时只能重新启动项目才能恢复。

三、多线程定时任务

基于注解设定多线程定时任务

1、创建多线程定时任务

@Controller
@EnableScheduling
@EnableAsync
public class MultithreadScheduleTask {
    @Async
    @Scheduled(fixedDelay = 1000)
    public void first() throws InterruptedException {
        System.out.println("第一个任务开始"+ LocalDateTime.now().toLocalTime()+"线程是"+Thread.currentThread().getName());
        System.out.println();
        Thread.sleep(3000);
    }
    @Async
    @Scheduled(fixedDelay = 2000)
    public void second(){
        System.out.println("第二个任务开始"+ LocalDateTime.now().toLocalTime()+"线程是"+Thread.currentThread().getName());
        System.out.println();
    }
}

2、启动测试

启动应用后,查看控制台:

第一个任务开始11:30:18.508线程是SimpleAsyncTaskExecutor-4

第二个任务开始11:30:18.510线程是SimpleAsyncTaskExecutor-5

第一个任务开始11:30:19.508线程是SimpleAsyncTaskExecutor-6

第一个任务开始11:30:20.508线程是SimpleAsyncTaskExecutor-8

第二个任务开始11:30:20.508线程是SimpleAsyncTaskExecutor-7

第一个任务开始11:30:21.509线程是SimpleAsyncTaskExecutor-9

第二个任务开始11:30:22.510线程是SimpleAsyncTaskExecutor-10

从控制台可以看出,第一个定时任务和第二个定时任务互不影响;

并且,由于开启了多线程,第一个任务的执行时间也不受其本身执行时间的限制,所以需要注意可能会出现重复操作导致数据异常。

猜你喜欢

转载自blog.csdn.net/zhou_fan_xi/article/details/87874838
今日推荐