Spring Boot实现定时任务的4种方式学习

实现定时任务的几种方式

  • Timer: 这是java自带的java.util.Timer类,这个类运行你调度一个java.util.TimerTask任务。使用这种方式可以让程序按照某一个频度执行,但不能在指定时间运行。一般用的较少。多线程并行处理定时任务,Timer运行多个TimeTask时,只要其中之一没有捕获抛出的异常,其它任务便会自动终止运行

  • ScheduledExecutorService: 也是jdk自带的一个类;是基于线程池设计的定时任务类,每个调度任务都会分配到线程池中的一个线程去执行,任务并发执行,互不影响

  • Spring Task: Spring3.0以后自带的task,可以将它看成一个轻量级的Quartz,而且使用起来比Quartz简单许多所有的定时任务都在同一线程上串行,想要异步执行需要自己添加线程池

  • Quartz: 这是一个功能比较强大的调度器,可以让你的程序在指定时间执行,也可以按照某一个频度执行,配置起来稍显复杂

使用Timer

public class TestTimer {
  public static void main(String[] args) {
    TimerTask timerTask = new TimerTask() {
      @Override
      public void run() {
        System.out.println("task run:" + System.currentTimeMillis());
      }
    };
    //多线程并行处理定时任务时,Timer运行多个TimeTask时,只要其中之一没有捕获抛出的异常,其它任务便会自动终止运行
    //并不推荐使用
    Timer timer = new Timer();
    //安排指定的任务在指定的时间开始进行重复的固定延迟执行,这里是延时10毫秒每3秒执行一次
    timer.schedule(timerTask, 10, 3000);
  }
}

使用ScheduledExecutorService

该方法跟Timer类似

public class TestScheduledExecutorService {
  public static void main(String[] args) {
    ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
    // 参数:1.任务体,2.首次执行的延时时间
    //      3.任务执行间隔,4.间隔时间单位
    service.scheduleAtFixedRate(new Runnable() {
      public void run() {
        System.out.println("task ScheduledExecutorService:" + System.currentTimeMillis());
      }
    }, 0, 3, TimeUnit.SECONDS);
  }
}

使用Spring Task

在spring boot中我们可以直接使用注解的方式来实现定时任务,非常简单,需要的依赖

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter</artifactId>
</dependency>
<!--通过注解的方式生成部分常用代码,减少重复代码编写-->
<dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
  <optional>true</optional>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-test</artifactId>
  <scope>test</scope>
</dependency>

创建任务类

@Slf4j
@Component
public class TestSpringTask {
  /**
   * 通过表达式来配置任务执行时间
   */
  @Scheduled(cron = "0/5 * * * * *")
  public void scheduled() {
    log.info("=====>>>>>使用cron:{}", System.currentTimeMillis());
  }

  /**
   * 按一定频率执行的定时任务
   */
  @Scheduled(fixedRate = 5000)
  public void scheduled1() {
    log.info("=====>>>>>使用fixedRate:{}", System.currentTimeMillis());
  }

  /**
   * 功能同fixedRate,但是可以配合initialDelay属性设置任务延时执行
   */
  @Scheduled(fixedDelay = 5000)
  public void scheduled2() {
    log.info("=====>>>>>使用fixedDelay:{}", System.currentTimeMillis());
  }
}

Application类上添加@EnableScheduling注解开启对定时任务的支持

@SpringBootApplication
//开启对定时任务的支持(所有的定时任务都在同一线程上串行)
@EnableScheduling
public class Application {
  public static void main(String[] args) {
    SpringApplication.run(Application.class);
  }
}

然后启动项目查看打印

2019-04-03 11:15:10.001  INFO 9252 --- [   scheduling-1] com.lx.timer.springtask.TestSpringTask   : =====>>>>>使用cron:1554261310001
2019-04-03 11:15:12.209  INFO 9252 --- [   scheduling-1] com.lx.timer.springtask.TestSpringTask   : =====>>>>>使用fixedRate:1554261312209
2019-04-03 11:15:12.211  INFO 9252 --- [   scheduling-1] com.lx.timer.springtask.TestSpringTask   : =====>>>>>使用fixedDelay:1554261312211
2019-04-03 11:15:15.002  INFO 9252 --- [   scheduling-1] com.lx.timer.springtask.TestSpringTask   : =====>>>>>使用cron:1554261315002

可以看到三个定时任务都已经执行,并且使同一个线程中串行执行,如果只有一个定时任务,这样做肯定没问题,当定时任务增多,如果一个任务卡死,会导致其他任务也无法执行,所以我们需要修改为多线程执行

修改Spring Task为多线程执行

新建一个AsyncConfig类

@Configuration
//开启异步事件的支持
@EnableAsync
public class AsyncConfig {
  /**
    * 以下参数均从yml配置文件中获取
    */
  @Value("${async.core-pool-size}")
  private int corePoolSize;
  @Value("${async.max-pool-size}")
  private int maxPoolSize;
  @Value("${async.queue-capacity}")
  private int quequeCapacity;

  @Bean
  public Executor taskExecutor() {
    ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    executor.setCorePoolSize(corePoolSize);
    executor.setMaxPoolSize(maxPoolSize);
    executor.setQueueCapacity(quequeCapacity);
    executor.initialize();
    return executor;
  }
}

然后再定时任务的类或者方法上添加@Async

@Slf4j
@Component
//对当前类开启异步(开启后每个方法的执行均在不同的线程中),也可以加在方法上
@Async
public class TestSpringTask {
  /**
   * 通过表达式来配置任务执行时间
   */
  @Scheduled(cron = "0/5 * * * * *")
  public void scheduled() {
    log.info("=====>>>>>使用cron:{}", System.currentTimeMillis());
  }

  /**
   * 按一定频率执行的定时任务
   */
  @Scheduled(fixedRate = 5000)
  public void scheduled1() {
    log.info("=====>>>>>使用fixedRate:{}", System.currentTimeMillis());
  }

  /**
   * 功能同fixedRate,但是可以配合initialDelay属性设置任务延时执行
   */
  @Scheduled(fixedDelay = 5000)
  public void scheduled2() {
    log.info("=====>>>>>使用fixedDelay:{}", System.currentTimeMillis());
  }
}

重启项目,可以看到每个任务都是在不同的线程

2019-04-03 11:19:47.020  INFO 13420 --- [ taskExecutor-4] com.lx.timer.springtask.TestSpringTask   : =====>>>>>使用fixedRate:1554261587020
2019-04-03 11:19:47.024  INFO 13420 --- [ taskExecutor-5] com.lx.timer.springtask.TestSpringTask   : =====>>>>>使用fixedDelay:1554261587024
2019-04-03 11:19:50.002  INFO 13420 --- [ taskExecutor-6] com.lx.timer.springtask.TestSpringTask   : =====>>>>>使用cron:1554261590002
2019-04-03 11:19:52.020  INFO 13420 --- [ taskExecutor-7] com.lx.timer.springtask.TestSpringTask   : =====>>>>>使用fixedRate:1554261592020
2019-04-03 11:19:52.025  INFO 13420 --- [ taskExecutor-8] com.lx.timer.springtask.TestSpringTask   : =====>>>>>使用fixedDelay:1554261592025
执行时间的配置

在上面的定时任务中,我们在方法上使用@Scheduled注解来设置任务的执行时间,并且使用3三种属性配置方式

  • fixedRate: 定义一个按照一定频率执行的定时任务
  • fixedDelay: 定义一个按一定频率执行的定时任务,与上边不同的是,该属性可以配合initialDelay,定义该任务延迟执行时间
  • cron: 通过表达式来配置任务执行时间
cron表达式详细参考下边的博客

https://blog.csdn.net/qq_33430083/article/details/89024540

整合Quartz

添加依赖
如果SpringBoot版本是2.0.0以后的,则在spring-boot-starter中已经包含了quart的依赖,则可以直接使用spring-boot-starter-quartz依赖:

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-quartz</artifactId>
    </dependency>

如果是1.5.9则要使用以下添加依赖:

<dependency>
  <groupId>org.quartz-scheduler</groupId>
  <artifactId>quartz</artifactId>
  <version>2.3.0</version>
</dependency>

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context-support</artifactId>
</dependency>

注意:如果项目中springboot使用的是springboot2.0以后的版本,去引用quartzspring-context-support包的话,quartz任务并不会执行

1.创建任务类
public class TestQuartz extends QuartzJobBean {

  /**
   * 执行定时任务
   * @param jobExecutionContext
   * @throws JobExecutionException
   */
  @Override
  protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
    System.out.println("quartz task" + System.currentTimeMillis());
  }
}
2.创建配置类QuartzConfig

执行方式有两种写法一种是使用CronScheduleBuilder类执行cron表达式
另一种是使用SimpleScheduleBuilder类指定间隔时间

public class QuartzConfig {
  @Bean
  public JobDetail teatQuartzDetail() {
    return JobBuilder.newJob(TestQuartz.class)
            .withIdentity("testQuartz").storeDurably().build();
  }

  @Bean
  public Trigger testQuartzTrigger() {
    //使用cron表达式
    CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule("*/5 * * * * ?");
    //指定间隔时间
//    SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule()
//            //设置时间周期单位秒,也可选择其他函数
//            .withIntervalInSeconds(3)
//            .repeatForever();
    return TriggerBuilder.newTrigger().forJob(teatQuartzDetail())
            .withIdentity("testQuartz")
            .withSchedule(cronScheduleBuilder)
            .build();
  }
}
3.启动项目

控制台打印如下,配置成功

quartz task1554273605007
quartz task1554273610000
quartz task1554273615000

Spring Task和Quarz的区别

Quartz在项目启动的时候会执行,使用注解的方式会在项目启动完成后时间算起执行,少一次执行调度

Demo地址

https://gitee.com/fengzxia/spring-boot-timer-learn

参考博客地址

https://juejin.im/post/5ca24fb1e51d454a490a4809?utm_source=gold_browser_extension

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值