@Schedule 如何解決定時任務推遲執行

前言

SpringBoot 實現定時任務很簡單,隻需要使用**@Scheduled**註解即可,但是該註解是實現的定時任務默認是單線程的,也就意味著多個定時任務執行時就可能導致線程堵塞,延緩定時任務的執行。

下面就一步一步來解決這個問題。

一、@Scheduled

1、代碼

// 啟用定時任務
@EnableScheduling 
@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}
@Component
public class Task {
    Logger logger = LoggerFactory.getLogger(Task.class);
	// 每五秒執行一次
    @Scheduled(cron = "0/5 * * * * ?")
    public void taskTestA() throws InterruptedException {
        logger.info("A:");
        TimeUnit.SECONDS.sleep(20);
    }
  
    // 每十秒執行一次
    @Scheduled(cron = "0/10 * * * * ?")
    public void taskTestB() {
        logger.info("B:");
    }
}

2、結果

代碼

由圖可知,首先這兩個定時任務都是單線程的,但是當定時A執行瞭一次後,由於定時A中有個休眠20秒,然後執行定時任務B,所以線程A第二次執行在25秒後才執行,這就是由於@Scheduled定時任務是單線程,造成的線程堵塞,導致定時任務推遲執行。

二、@Scheduled + 配置線程池

1、代碼

和前面@Scheduled 相比,僅僅增加瞭配置線程池

// 若不設置默認為單線程,這裡設置使用線程池,大小為4
spring:
  task:
    scheduling:
      pool:
        size: 4

2、結果

由圖可知,增加瞭線程池,這樣使得定時任務A和B在不同的線程進行執行,但是定時任務A的第二次執行,依舊是在25秒後執行,由此可知這種方式其實解決的是不同定時任務之間的進程堵塞。

三、@Scheduled + @Async

1、代碼

和前面相比,僅僅增加瞭配置

// 啟用異步,動態創建線程
@EnableAsync  
@EnableScheduling
@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}
@Component
public class Task { 
    Logger logger = LoggerFactory.getLogger(Task.class);
    // 異步,動態創建線程
    @Async
    @Scheduled(cron = "0/5 * * * * ?")
    public void taskTestA() throws InterruptedException {
        logger.info("A:");
        TimeUnit.SECONDS.sleep(20);
    }
    // 異步,動態創建線程
    @Async
    @Scheduled(cron = "0/10 * * * * ?")
    public void taskTestB() {
        logger.info("B:");
    }
}

2、結果

由圖可知,啟用瞭異步,使用瞭spring 默認的線程池,動態創建線程,這樣使得定時任務A和B在不同的線程進行執行,同時任務A的多次運行也是異步執行,這樣就能確保所有定時任務不會延遲執行!

以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。

推薦閱讀: