springBoot中使用定時任務

簡單示例

導入依賴

springBoot已經默認集成了定時任務的依賴,只須要引入基本的依賴就可使用定時任務。java

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-parent</artifactId>
        <version>2.0.0.RELEASE</version>
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <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>
        </dependency>

    </dependencies>

啓動類配置

在啓動類中須要加入@EnableScheduling註解,意思是開啓定時任務。spring

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;

/**
 * Author: YaoQi
 * Date: 2018/9/28 21:37
 * Description: springBoot schedule
 */
@SpringBootApplication
@EnableScheduling
public class ScheduleApp {

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

定時任務Demo

寫一個定時任務demo,每秒種打印一第二天志,並打印當前時間驗證當前任務執行週期。多線程

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

/**
 * Author: YaoQi
 * Date: 2018/9/28 21:40
 * Description: Scheduled Task
 */
@Service
public class ScheduleTask {

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

    @Scheduled(cron = "*/1 * * * * ?")
    public void execute() {
        logger.info("print word.");
        logger.info(String.valueOf(System.currentTimeMillis()));
    }
}

運行結果:ide

運行結果

示例分析

從上圖的結果中看:該任務基本是每秒種執行一次,若是不手動中止,程序會一直執行下去,而且從日誌中看,這個任務的執行週期是1s左右,恰好和設置的cron表達式一致;而且執行這個任務的線程一直是poll-1-thread-1這個線程。這就意味着,這個定時任務啓動是由單獨的一個線程去執行的。spring-boot

這時候,可能會有幾個問題:ui

若是任務執行的時間比執行週期要短,這個任務會怎麼執行?線程

若是有多個任務執行,還會是一個線程去執行這個任務嗎?日誌

首先驗證第一個問題,當任務執行的時間比執行週期短時,任務的執行狀況。code

@Scheduled(cron = "*/1 * * * * ?")
    public void execute() {
        logger.info("print word.");
        logger.info(String.valueOf(System.currentTimeMillis()));
        try {
            Thread.sleep(6000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

執行結果:每次任務的執行時間間隔爲7秒,而且是同一個線程在執行。xml

執行結果

若是有多個任務執行,任務的執行狀況。

@Scheduled(cron = "*/1 * * * * ?")
    public void execute() {
        logger.info("print word.");
        try {
            Thread.sleep(6000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Scheduled(cron = "*/1 * * * * ?")
    public void execute1() {
        logger.info(String.valueOf(System.currentTimeMillis()));
        logger.info("write message.");
    }

執行結果:

執行結果

執行結果:第二個每秒執行一次的任務的並無安裝設定的執行週期執行,運行結果並無達到預期。而且兩個任務都是由同一個線程去運行。

多任務模式

示例分析中問題2的緣由就是執行多個任務並非多個線程執行,致使執行第一個任務時,第二個任務進入等待狀態。springBoot中提供了多線程運行定時任務的方式。

@Configuration
public class ScheduleConfig implements SchedulingConfigurer {

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.setScheduler(Executors.newScheduledThreadPool(3));
    }
}

增長一個配置類,設置線程池,並設置線程池大小,這裏的線程池大小就仁者見仁了,和你程序中的任務的個數有關係,也和機器的核數有關係。

經過配置線程池就能讓每一個任務獨立執行,不受其餘任務的影響,由於是在不一樣的線程中執行的,但若是涉及到公共資源就另當別論了。

執行結果:

在不一樣的線程中執行

配置執行週期

上述中的執行週期都是以cron表達式定義的,這種方式最靈活,可是上文中的表達式都寫到代碼中去了,不便於修改,這裏提供一種配置方式,直接用表達式獲取yml中的配置信息。

scheduleTask:
  cron1: "*/1 * * * * ?"
  cron2: "*/1 * * * * ?"

在yml中添加cron的配置信息。而後在Java註解中能夠直接獲取。

@Scheduled(cron = "${scheduleTask.cron2}")
    public void execute1() {
        logger.info(String.valueOf(System.currentTimeMillis()));
        logger.info("write message.");
    }
相關文章
相關標籤/搜索