Springboot定时任务踩坑记录

39次阅读

共计 3460 个字符,预计需要花费 9 分钟才能阅读完成。

前言
在使用 Springboot 整合定时任务,发现当某个定时任务执行出现执行时间过长的情况时会阻塞其他定时任务的执行。
问题定位
后续通过翻查 Springboot 的文档以及打印日志(输出当前线程信息)得知问题是由于 Springboot 默认使用只要 1 个线程处理定时任务。
问题复盘
需要注意示例的 Springboot 版本为 2.1.3.RELEASE。
关键 pom 文件配置
<!– 继承父项目 –>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
<relativePath/> <!– lookup parent from repository –>
</parent>

… 省略非关键配置

<!– 引入依赖 –>
<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>
<scope>test</scope>
</dependency>
</dependencies>
定时任务
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

/**
* 定时任务
* @author RJH
* create at 2019-03-29
*/
@Component
public class SimpleTask {

private static Logger logger= LoggerFactory.getLogger(SimpleTask.class);

/**
* 执行会超时的任务,定时任务间隔为 5000ms(等价于 5s)
*/
@Scheduled(fixedRate = 5000)
public void overtimeTask(){
try {
logger.info(“current run by overtimeTask”);
// 休眠时间为执行间隔的 2 倍
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

/**
* 正常的定时任务
*/
@Scheduled(fixedRate = 5000)
public void simpleTask(){
logger.info(“current run by simpleTask”);
}
}
启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
@EnableScheduling
public class TaskDemoApplication {

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

}
运行结果
… 省略非关键信息
2019-03-29 21:22:38.410 INFO 59731 — [scheduling-1] com.rjh.task.SimpleTask : current run by simpleTask
2019-03-29 21:22:38.413 INFO 59731 — [scheduling-1] com.rjh.task.SimpleTask : current run by overtimeTask
2019-03-29 21:22:48.413 INFO 59731 — [scheduling-1] com.rjh.task.SimpleTask : current run by simpleTask
2019-03-29 21:22:48.414 INFO 59731 — [scheduling-1] com.rjh.task.SimpleTask : current run by overtimeTask
2019-03-29 21:22:58.418 INFO 59731 — [scheduling-1] com.rjh.task.SimpleTask : current run by simpleTask
2019-03-29 21:22:58.418 INFO 59731 — [scheduling-1] com.rjh.task.SimpleTask : current run by overtimeTask
2019-03-29 21:23:08.424 INFO 59731 — [scheduling-1] com.rjh.task.SimpleTask : current run by simpleTask
2019-03-29 21:23:08.424 INFO 59731 — [scheduling-1] com.rjh.task.SimpleTask : current run by overtimeTask
2019-03-29 21:23:18.425 INFO 59731 — [scheduling-1] com.rjh.task.SimpleTask : current run by simpleTask
2019-03-29 21:23:18.426 INFO 59731 — [scheduling-1] com.rjh.task.SimpleTask : current run by overtimeTask

结果分析
由运行结果可以看出:

每次定时任务的运行都是由 scheduling- 1 这个线程处理
正常运行的 simpleTask 被 overtimeTask 阻塞导致了运行间隔变成了 10 秒

后面通过查阅 Springboot 的文档也得知了定时任务默认最大运行线程数为 1。
解决方案
由于使用的 Springboot 版本为 2.1.3.RELEASE,所以有两种方法解决这个问题
使用 Springboot 配置
在配置文件中可以配置定时任务可用的线程数:
## 配置可用线程数为 10
spring.task.scheduling.pool.size=10
自定义定时任务的线程池
使用自定义的线程池代替默认的线程池
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;

/**
* 定时任务配置类
* @author RJH
* create at 2019-03-29
*/
@Configuration
public class ScheduleConfig {

/**
* 此处方法名为 Bean 的名字,方法名无需固定
* 因为是按 TaskScheduler 接口自动注入
* @return
*/
@Bean
public TaskScheduler taskScheduler(){
// Spring 提供的定时任务线程池类
ThreadPoolTaskScheduler taskScheduler=new ThreadPoolTaskScheduler();
// 设定最大可用的线程数目
taskScheduler.setPoolSize(10);
return taskScheduler;
}
}

正文完
 0