本文主要叙述SpringBoot——@Scheduled的自定義周期性線程池解決任務延時執行問題。
關注微信公衆号:CodingTechWork,一起學習進步。
問題
在使用
Spring
中的
@Scheduled
注解設定定時任務時,遇到這樣2個問題:
- 定時任務未按時執行,現象是延後了一段時間才執行定時任務。
- 多個定時任務有時間重疊時,無法并發排程執行。
分析
出現上面問題現象的根因是Spring的定時任務預設是單線程執行,是以會在某些場景下造成阻塞。當然我們可以通過
@Async
注解來異步執行這些并發的
@Scheduled
注解的定時任務,而
@Async
線程池容量是100,當超過100個線程并發執行時,則剩下的定時任務會等待之前的線程釋放,不會自行擴容。
既然@Async是個定值大小的線程池,還是有出現定時任務延時執行的問題,是以下面我們可以通過其他方式來自定義線程池大小。
解決方式
通過自定義配置線程池來解決問題。
package com.andya.selfcode.conf;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import java.util.concurrent.*;
/**
* @author Andya
* @create 2021-03-31
*/
@Slf4j
@Configuration
public class ScheduleConfig implements SchedulingConfigurer {
//自定義線程池大小,可配置。代碼中預設10個
@Value("${threadPool.schedule.coreSize: 10}")
public int SCHEDULE_CORE_SIZE;
//自定義線程池名稱
public static final String THREAD_NAME_WITH_SCHEDULE = "schedule-thread-%d";
@Override
public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
// scheduledTaskRegistrar.setScheduler(Executors.newScheduledThreadPool(SCHEDULE_CORE_SIZE));
scheduledTaskRegistrar.setScheduler(this.buildSchedulerThreadPool());
System.out.println("Scheduler threadpool core_size: " + SCHEDULE_CORE_SIZE);
}
/**
* Spring的@Scheduled的自定義周期性線程池
* @return
*/
@Bean(value = "scheduleThreadPool")
public ExecutorService buildSchedulerThreadPool() {
ThreadFactory threadFactory = new ThreadFactoryBuilder()
.setNameFormat(THREAD_NAME_WITH_SCHEDULE).build();
/**
* 1. CallerRunsPolicy : 這個政策重試添加目前的任務,他會自動重複調用 execute() 方法,直到成功。
2. AbortPolicy : 對拒絕任務抛棄處理,并且抛出異常。
3. DiscardPolicy : 對拒絕任務直接無聲抛棄,沒有異常資訊。
4. DiscardOldestPolicy : 對拒絕任務不抛棄,而是抛棄隊列裡面等待最久的一個線程,然後把拒絕任務加到隊列。
不寫則為預設的AbortPolicy政策。
*/
ScheduledExecutorService threadPool = new ScheduledThreadPoolExecutor(
SCHEDULE_CORE_SIZE,
threadFactory);
return threadPool;
}
}
燒不死的鳥就是鳳凰