美文网首页0.面试技能
SpringBoot @Scheduled多线程执行

SpringBoot @Scheduled多线程执行

作者: fantasticMao | 来源:发表于2020-01-06 22:34 被阅读0次

问题

在用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注解参数:

  • cron:cron表达式,指定任务在特定时间执行;
  • fixedDelay:表示上一次任务执行完成后多久再次执行,参数类型为long,单位ms;
  • fixedDelayString:与fixedDelay含义一样,只是参数类型变为String;
  • fixedRate:表示按一定的频率执行任务,参数类型为long,单位ms;
  • fixedRateString: 与fixedRate的含义一样,只是将参数类型变为String;
  • initialDelay:表示延迟多久再第一次执行任务,参数类型为long,单位ms;
  • initialDelayString:与initialDelay的含义一样,只是将参数类型变为String;
  • zone:时区,默认为当前时区。

线程池拒绝策略

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

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

相关文章

网友评论

    本文标题:SpringBoot @Scheduled多线程执行

    本文链接:https://www.haomeiwen.com/subject/buslactx.html