在我們現在的項目中,或多或少的都會涉及到定時任務,Spring在3.0之后引入了SpringSchedule,這讓我們在使用Spring的時候,可以很容易的整合SpringSchedule.但是好用歸好用,用的時候還是有一些點注意的.
SpringSchedule 中提供的定時任務,默認是單線程執行的,也就是說如果任務較多,或者某一個任務執行耗時比較久,那么顯然易見,會很容易導致其余任務排隊以及阻塞.
既然存在這種問題,那么怎么去避免這種問題?這時候大家很容易想到的就是使用線程池,多個線程去跑定時任務.沒錯,正確的解決方案就是配置線程池.
之所以默認是單線程執行的,是因為當我們沒有配置taskSchedule的時候,默認創建的是一個單線程的線程池。具體代碼解析參考:https://blog.csdn.net/weixin_40318210/article/details/78149692
先看一下沒配置線程池的情況下的任務執行線程日志:
定時任務業務類的代碼如下:
@Component
public class TaskConfig {
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
@Scheduled(fixedDelayString = "5000") //單機
public void getTask1() throws InterruptedException {
//競爭鎖邏輯代碼 .....
System.out.println("任務1,當前時間:" + dateFormat.format(new Date())+",線程號:"+Thread.currentThread().getName());
//throw new RuntimeException("xxxxx");
Thread.sleep(10000);
}
@Scheduled(cron = "0/5 * * * * ?")
public void getTask2() {
System.out.println("任務2,當前時間:" + dateFormat.format(new Date())+",線程號:"+Thread.currentThread().getName());
}
}
任務執行日志為:

可以看到執行這兩個任務的線程總是同一個線程.
那么我們現在加入線程池的配置,配置代碼如下:
@Configuration
public class ScheduleConfig implements SchedulingConfigurer {
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(taskExecutor());
}
//配置線程池---觸發器和任務共用的
@Bean(destroyMethod="shutdown")
public Executor taskExecutor() {
return Executors.newScheduledThreadPool(10);
}
}
接下來我們再觀察一下定時任務的執行信息:

現在看到是加入線程池后,每次執行的定時任務的線程在不斷的變化,同時這兩個任務也可以並行的執行,可以避免任務的阻塞與排隊.
如果你的代碼中使用了SpringSchedule,而且還沒有使用線程池,那么趕緊去修改吧.
