0.面试技能

SpringBoot @Scheduled多线程执行

2020-01-06  本文已影响0人  fantasticMao

问题

在用springboot框架做定时任务的时候,大部分情况都是直接通过@Scheduled注解来指定定时任务的。但是当你有多个定时任务时,@Scheduled并不一定会按时执行。
因为使用@Scheduled的定时任务虽然是异步执行的,但是,默认不同的定时任务之间并不是并行的。

查看org.springframework.scheduling.config.ScheduledTaskRegistrar源码即可发现

protected void scheduleTasks() {
        if (this.taskScheduler == null) {
            this.localExecutor = Executors.newSingleThreadScheduledExecutor();
            this.taskScheduler = new ConcurrentTaskScheduler(this.localExecutor);
        }
        if (this.triggerTasks != null) {
            for (TriggerTask task : this.triggerTasks) {
                addScheduledTask(scheduleTriggerTask(task));
            }
        }
        if (this.cronTasks != null) {
            for (CronTask task : this.cronTasks) {
                addScheduledTask(scheduleCronTask(task));
            }
        }
        if (this.fixedRateTasks != null) {
            for (IntervalTask task : this.fixedRateTasks) {
                addScheduledTask(scheduleFixedRateTask(task));
            }
        }
        if (this.fixedDelayTasks != null) {
            for (IntervalTask task : this.fixedDelayTasks) {
                addScheduledTask(scheduleFixedDelayTask(task));
            }
        }
    }

当未手动指定taskScheduler时,会通过Executors.newSingleThreadScheduledExecutor()创建默认的单线程线程池,且该线程池的拒绝策略为AbortPolicy,这种策略在线程池无可用线程时丢弃任务,并抛出异常RejectedExecutionException

解决方法

添加配置类

import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;

import java.util.concurrent.Executors;

/**
 * @author maokeluo
 * @description 多隆镇楼,bug退散🙏🙏🙏
 * 定时任务线程池配置
 * @date 2019/12/31
 */
@Configuration
public class ScheduleConfig implements SchedulingConfigurer {
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        //显式为Scheduler指定线程池
        taskRegistrar.setScheduler(Executors.newScheduledThreadPool(10));
    }
}

补充

@Scheduled注解参数:

线程池拒绝策略

接口java.util.concurrent.RejectedExecutionHandler提供了拒绝任务处理的自定义方法。在java.util.concurrent.ThreadPoolExecutor中已经包含四种拒绝策略。

  1. AbortPolicy拒绝策略:抛出运行时异常RejectedExecutionException,这种策略丢弃任务,并抛出异常(jdk默认策略)。
  2. DiscardPolicy拒绝策略:不能执行的任务将被丢弃,这种策略什么都没做。
  3. DiscardOldestPolicy拒绝策略:如果执行程序尚未关闭,则位于工作队列头部的任务将被删除,然后重试执行程序。
  4. CallerRunsPolicy拒绝策略:线程调用运行该任务的execute本身。此策略提供简单的反馈控制机制,能够减缓新任务的提交速度。这个策略不想放弃执行任务。但是由于池中已经没有任何资源了,那么就直接使用调用该execute的线程本身来执行。
上一篇 下一篇

猜你喜欢

热点阅读