0
点赞
收藏
分享

微信扫一扫

SpringBoot 定时任务实践、定时任务按指定时间执行


Q1. springboot怎样创建定时任务?

很显然,人人都知道,@Scheduled(cron = ".....")

Q2. 如上所示创建了定时任务却未能执行是为什么?

如果你的cron确定没写错的话

cron表达式是否合法,可参考此处,https://tool.lu/crontab/,选择Spring表达式。

那么可能是你启动类少了一个注解:@EnableScheduling 如下图

SpringBoot 定时任务实践、定时任务按指定时间执行_Scheduled Async

Q3. 多个定时任务,未能严格按照指定的时间执行,为什么?

比如有4个定时任务,分别是每天凌晨的1点整、2点整、3点整、4点整执行;
但观察日志发现并不是。
比如1点整开始执行第一个(如果会执行很久的话)
2点半才开始执行第2个
后面的以此类推都不一定严格按照指定时间。
那么,为什么?

因为springboot里面的定时任务默认是单线程执行的。后面的定时任务会排队、顺延。
比如Job1执行了1.5h,Job2的时间尽管到了,但没有线程可用,就只能等Job1完成之后才执行。
所以就会出现顺延现象。

Q4. 如何确保定时任务在特定时间执行?

这里思路就很简单了,多线程,即创建一个线程池,比如4个线程,并且指定使用这个线程池里的线程来做这4个定时任务,肯定是足够的。
这样的话就不会依次影响了。

注意,只给定时任务增加@Async注解是不够的。

step1,初始化线程池

文件1, SchedulerConfig.java

package cn.xxx.starter.config;

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

import javax.annotation.Resource;

/**
 * @author 
 * @date 2024/4/2 14:22
 * @desc
 */
@Configuration
public class SchedulerConfig implements SchedulingConfigurer {

    @Resource
    private ThreadPoolTaskScheduler threadPoolTaskScheduler;

    @Override
    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
        scheduledTaskRegistrar.setTaskScheduler(threadPoolTaskScheduler);
    }
}

文件2, ThreadPoolTaskSchedulerConfig.java

package cn.xxx.starter.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;

import java.util.concurrent.Executor;

/**
 * @author 
 * @date 2024/4/1 17:45
 * @desc
 */
@Configuration
@EnableAsync
public class ThreadPoolTaskSchedulerConfig {

    private int corePoolSize = 4;

    @Bean
    public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
        ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
        //线程池大小为10
        threadPoolTaskScheduler.setPoolSize(corePoolSize);
        //设置线程名称前缀
        threadPoolTaskScheduler.setThreadNamePrefix("AsyncJob-thread-");
        //关键点: 设置线程池关闭的时候等待所有任务都完成再继续销毁其他的Bean
        threadPoolTaskScheduler.setWaitForTasksToCompleteOnShutdown(true);
        //关键点:设置线程池中任务的等待时间,如果超过这个时候还没有销毁就强制销毁,以确保应用最后能够被关闭,而不是阻塞住
        threadPoolTaskScheduler.setAwaitTerminationSeconds(60 * 60);
        threadPoolTaskScheduler.initialize();
        return threadPoolTaskScheduler;
    }
}

step2 ,启动定时任务时指定使用此线程池

XxxxJob.java

package cn.xxx.starter.task.job;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class Job1{

    @Async(value = "threadPoolTaskScheduler")
    @Scheduled(cron = "0 30 */1 * * ?")
    public void execute() {       
        try {
          //......
        }catch (Exception e){
            log.error("Job1出错 e = {}, stackTrace = {} ", e.getMessage(), JSON.toJSONString(e.getStackTrace()));
        }finally {
            log.info("Job1结束");       
        }
   }
}


举报

相关推荐

0 条评论