天天看點

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

本文主要叙述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;
    }
}

           

燒不死的鳥就是鳳凰