場景:使用spring框架自帶的定時注解來實現定時任務A,定時任務B
需求:定時任務A的每次任務啟動卡死,不能影響下次定時任務的觸發,更不能影響定時任務B的執行
問題:spring框架自帶的定時,定時任務開啟成功,但所有的任務都是在同一個線程池中的同一個線程來完成的。在實際開發過程中,我們當然不希望所有的任務都運行在一個線程中,此時需要各個定時任務是相互獨立的。
1.定時任務A和定時任務B是相互獨立的,但是定時任務A的某個任務卡死是會影響A的下一個任務出發的,每一個任務都起一條線程去執行,要求必須每個執行完畢后才能再次執行,所以不能開啟異步執行
/**
* 實現SchedulingConfigurer ,重寫configureTasks 用多線程
*/
@Component
public class SpringCornTask implements SchedulingConfigurer {
@Autowired
@Qualifier("updateAsyncExecutor")
ThreadPoolTaskScheduler threadPoolTaskScheduler;
//所有加了注解@Scheduled都是用的同一個線程池threadPoolTaskScheduler的線程,同時線程的名字updateAsyncExecutor-
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(threadPoolTaskScheduler);
}
}
/**
* 創建定時任務線程池
*/
@Bean("updateAsyncExecutor")
public ThreadPoolTaskScheduler updateAsyncExecutor() {
ThreadPoolTaskScheduler executor = new ThreadPoolTaskScheduler();
executor.setPoolSize(3);
executor.setThreadNamePrefix("updateAsyncExecutor-");
//用來設置線程池關閉的時候等待所有任務都完成再繼續銷毀其他的Bean
executor.setWaitForTasksToCompleteOnShutdown(true);
//該方法用來設置線程池中任務的等待時間,如果超過這個時候還沒有銷毀就強制銷毀,以確保應用最后能夠被關閉,而不是阻塞住。
executor.setAwaitTerminationSeconds(9000);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());
return executor;
}
/**
* 定時任務A
*/
@Scheduled(cron = "0 0 0/4 * * ?")
public void updateRecord() throws IOException {
log.info("開始執行定時任務===" + new Date() + "===" + Thread.currentThread().getName());
}
2.實現結果是定時任務A和定時任務B是相互獨立的,而且定時任務A的某個任務卡死是不會影響A的下一個任務出發的,同時擔心A和B如果共用同一個線程池,如果任務A卡死,不斷起線程,不斷卡死,會把線程池任務占用完畢,最終會影響到B,更何況A和B的執行頻率差異很大
/**
* 創建B的線程池
*/
@Bean("cleanAsyncExecutor")
public ThreadPoolTaskScheduler cleanAsyncExecutor() {
ThreadPoolTaskScheduler executor = new ThreadPoolTaskScheduler();
executor.setPoolSize(3);
executor.setThreadNamePrefix("cleanAsyncExecutor-");
executor.setWaitForTasksToCompleteOnShutdown(true);
//該方法用來設置線程池中任務的等待時間,如果超過這個時候還沒有銷毀就強制銷毀,以確保應用最后能夠被關閉,而不是阻塞住。
executor.setAwaitTerminationSeconds(9000);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());
return executor;
}
//同理,創建A的線程池
.................
/**
* 定時任務A,同時開啟異步,指定線程池updateAsyncExecutor
*/
@Async("updateAsyncExecutor")
@Scheduled(cron = "0 0 0/5 * * ?")
public void updateCompareDataRecord() throws IOException {
log.info("開始執行定時任務A===" + new Date() + "===" + Thread.currentThread().getName());
}
/**
* 定時任務B,同時開啟異步,指定線程池updateAsyncExecutor
*/
@Async("cleanAsyncExecutor")
@Scheduled(cron = "0 0 0 1/1 * ?")
public void cleanDataRecord() throws IOException {
log.info("開始執行定時任務AB===" + new Date() + "===" + Thread.currentThread().getName());
}
可以參考:spring scheduled單線程和多線程使用過程中的大坑!!不看到時候絕對后悔!! - hellodev - 博客園 (cnblogs.com)