Springboot定時任務踩坑記錄

前言

在使用Springboot整合定時任務,發現當某個定時任務執行出現執行時間過長的狀況時會阻塞其餘定時任務的執行。spring

問題定位

後續經過翻查Springboot的文檔以及打印日誌(輸出當前線程信息)得知問題是因爲Springboot默認使用只有1個線程的單線程池處理定時任務。spring-boot

問題覆盤

須要注意示例的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
...

結果分析

由運行結果能夠看出:日誌

  1. 每次定時任務的運行都是由scheduling-1這個線程處理
  2. 正常運行的simpleTaskovertimeTask阻塞致使了運行間隔變成了10

後面經過查閱Springboot的文檔也得知了定時任務默認最大運行線程數爲1code

解決方案

因爲使用的Springboot版本爲2.1.3.RELEASE,因此有兩種方法解決這個問題繼承

使用Springboot配置

在配置文件中能夠配置定時任務可用的線程數:接口

## 配置可用線程數爲10
spring.task.scheduling.pool.size=10

自定義定時任務的線程池

使用自定義的線程池代替默認的線程池ci

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;
    }
}
相關文章
相關標籤/搜索