Springboot定時任務踩坑記錄
前言
在使用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.410INFO 59731 --- [scheduling-1] com.rjh.task.SimpleTask: current run by simpleTask 2019-03-29 21:22:38.413INFO 59731 --- [scheduling-1] com.rjh.task.SimpleTask: current run by overtimeTask 2019-03-29 21:22:48.413INFO 59731 --- [scheduling-1] com.rjh.task.SimpleTask: current run by simpleTask 2019-03-29 21:22:48.414INFO 59731 --- [scheduling-1] com.rjh.task.SimpleTask: current run by overtimeTask 2019-03-29 21:22:58.418INFO 59731 --- [scheduling-1] com.rjh.task.SimpleTask: current run by simpleTask 2019-03-29 21:22:58.418INFO 59731 --- [scheduling-1] com.rjh.task.SimpleTask: current run by overtimeTask 2019-03-29 21:23:08.424INFO 59731 --- [scheduling-1] com.rjh.task.SimpleTask: current run by simpleTask 2019-03-29 21:23:08.424INFO 59731 --- [scheduling-1] com.rjh.task.SimpleTask: current run by overtimeTask 2019-03-29 21:23:18.425INFO 59731 --- [scheduling-1] com.rjh.task.SimpleTask: current run by simpleTask 2019-03-29 21:23:18.426INFO 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; } }