SpringBoot(四)定时任务(Scheduling)

一.SpringBoot中开启定时任务

在spirngboot中使用定时任务非常简单,只需要在启动类上增加一个@EnableScheduling注解即可。

1
2
3
4
5
6
7
8
9
@SpringBootApplication
@EnableScheduling
public class Application {

public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}

}

二.定时任务的创建

对定时任务的类增加@Component注解,加入Spring的容器管理中

1
2
3
4
5
6
@Component
public class ScheduleJob {

......

}

主要有三种定时的方式:

1.fixedRate

该属性的含义是上一个调用开始后再次调用的延时(不用等待上一次调用完成),这样就可能会存在任务重复执行的问题,所以不是建议使用,但数据量如果不大时在配置的间隔时间内可以执行完也是可以使用的。配置示例如下图5所示:

1
2
3
4
5
@Scheduled(fixedRate = 1000 * 1)
public void fixedRateTask() throws InterruptedException {
TimeUnit.SECONDS.sleep(2);
System.out.println("执行 fixedRate 任务的时间:" + new Date(System.currentTimeMillis()));
}

控制台输出:

任务触发的间隔都是2秒,说明该方法并没有等到执行完再开始下次执行(如果等待执行完应该需要3秒),而且看起来像一个单线程加队列的方式在执行。

2.fixedDelay

该属性的功效与上面的fixedRate则是相反的,配置了该属性后会等到方法执行完成后延迟配置的时间再次执行该方法。

1
2
3
4
5
@Scheduled(fixedDelay = 1000 * 1)
public void fixedDelayTask() throws InterruptedException {
TimeUnit.SECONDS.sleep(3);
System.out.println("执行 fixedDelay 任务的时间:" + new Date(System.currentTimeMillis()));
}

控制台输出结果:

3.cron表达式

1
2
3
4
@Scheduled(cron = "0/10 * * * * ?")
public void cronTask() {
System.out.println("执行 cron 任务的时间:" + new Date(System.currentTimeMillis()));
}

控制台输出:

三.定时任务线程池

默认情况下,如果什么都不进行配置,就会导致一个问题,系统中所有的定时任务都是使用的一个线程去执行的,也就是说,如果如果同一个时刻有2个定时任务需要执行,那么只可能有一个定时任务在执行,如果要解决这个问题可以定义一个自定的任务调度线程池即可。

解决方案:

By default, will be searching for an associated scheduler definition: either a unique {@link org.springframework.scheduling.TaskScheduler} bean in the context, or a {@code TaskScheduler} bean named “taskScheduler” otherwise; the same lookup will also be performed for a {@link java.util.concurrent.ScheduledExecutorService} bean. If neither of the two is resolvable, a local single-threaded default scheduler will be created and used within the registrar.

上面这一段是从org.springframework.scheduling.annotation.EnableScheduling这个注解类上的一段注释。大致上就是我们定义一个TaskScheduler类型的bean即可解决这个问题。

对于定时任务类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Component
public class ScheduleTreadTest {

@Scheduled(cron = "0/3 * * * * ?")
public void task01() {
System.out.println(Thread.currentThread().getName() + "----> task01");
}

@Scheduled(cron = "0/2 * * * * ?")
public void task02() {
System.out.println(Thread.currentThread().getName() + "----> task02");
}

@Scheduled(cron = "0/3 * * * * ?")
public void task03() {
System.out.println(Thread.currentThread().getName() + "----> task03");
}

}

如果不定义线程池,控制台输出如下,可以看到不同的定时任务是同一个线程在执行:

在配置类或者启动类中增加定时任务的线程池:

控制台输出:


本节示例代码已上传到github: https://github.com/liaosilzu2007/spring-boot.git

------ 本文完 ------