SpringBoot——@Scheduled的自定義周期性線程池解決任務延時執行問題


關注微信公眾號:CodingTechWork,一起學習進步。

問題

  在使用Spring中的@Scheduled注解設置定時任務時,遇到這樣2個問題:

  1. 定時任務未按時執行,現象是延后了一段時間才執行定時任務。
  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;
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM