spring task定时任务

springboot 中使用

1.静态定时任务

添加注解 @EnableScheduling

在使用需要定时任务的方法上添加

@Scheduled(cron = "0 0/1 * * * ?") 这里使用了cron表达式

@Scheduled 的参数

1、cron cron表达式

2、zone 设置时区

比如@Scheduled(cron = "0 0/1 * * * ?", zone = "UTC")

zone 时区只对cron表达式有效

3、fixedDelay 任务执行间隔 单位毫秒 long类型

前一个任务执行完成后 后面的任务需要等待相应的时间间隔才能继续执行

fixedDelayString 任务执行间隔 单位毫秒 和fixedDelay一样这里是使用的字符串

@Scheduled(fixedDelayString=“1000”) 1秒执行一次

4、fixedRate 按照一定速率运行 单位毫秒

@Scheduled(fixedRate =5000) 表示5s执行一次任务 如果有一次任务耗时较长30s,则该任务完成后后面的任务会陆续执行尽量保证以每5s每个的速率执行完任务

fixedRateString 和 fixedRate 一样 这里是字符串形式

5、initialDelay 第一次执行延迟的毫秒数

 

 

 

默认使用单线程同步执行 我们可以配置使用多线程异步执行

使用注解 @EnableAsync 开启异步执行

在定时方法上添加@Async即可

 

/**
 * 使用spring task 处理定时任务
 * 也可以使用 Quartz
 * 注意默认 spring task 是以单线程运行如果有些任务执行时间过长的话会造成阻塞
 * 导致下一次任务延迟执行 这里可以使用@EnableAsync 开启多线程任务
 * 在相应的任务方法上添加@async注解即可
 * @author 超
 * @description
 * @createDate 2022/3/12 11:51
 */
@Component
@EnableScheduling
@EnableAsync
public class ScheduledService {
​
    /**
     * 这里自定义线程池的配置信息
     * 如果想使用默认的不需要配置
     * @date 2022/3/12 14:26
     * @return org.springframework.core.task.TaskExecutor
     */
    @Bean
    public TaskExecutor taskExecutor(){
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        taskExecutor.setCorePoolSize(2);
        taskExecutor.setMaxPoolSize(5);
        // 非核心线程超过多长时间没有活跃 自动删除
        taskExecutor.setKeepAliveSeconds(300);
        // 阻塞队列的大小
        taskExecutor.setQueueCapacity(10000);
        return taskExecutor;
    }
​
    // 格式 秒 分 时 天 月 星期 年份
    /*
     `*` 字符代表所有可能的值
     `/` 字符用来指定数值的增量
         比如:(分钟)里的“0/15”表示从第0分钟开始,每15分钟
     `?` 字符仅被用于天(月)和天(星期)两个子表达式,表示不指定值
         当2个子表达式其中之一被指定了值以后,为了避免冲突,需要将另一个子表达式的值设为?
     `L` 字符仅被用于天(月)和天(星期)两个子表达式,它是单词“last”的缩写
         比如: 3L  指定了月标识  哪个月的最后3天    指定了星期 标识 哪个星期的最后3天
      `W` 字符代表着*日(Mon-Fri),并且仅能用于日域中。它用来指定离指定日的最*的一个*日。大部分的商业处理都是基于工作周的,所以W字符可能是非常重要的。
          日域中的15W意味着 “离该月15号的最*一个*日。” 假如15号是星期六,那么 trigger 会在14号(星期五)触发,因为星期四比星期一离15号更*。
      `C` 代表“Calendar”的意思。它的意思是计划所关联的日期,如果日期没有被关联,则相当于日历中所有日期。
          比如 5C在日期字段中就相当于日历5日以后的第一天。1C在星期字段中相当于星期日后的第一天
     */
    @Async
    @Scheduled(cron = "0 0/1 * * * ?")
    public void testWork(){
        System.out.println(Thread.currentThread().getName() +" 定时任务执行了:" + (LocalDateTime.now().toEpochSecond(ZoneOffset.UTC) - LocalDateTime.of(2022,3,12, 0, 0).toEpochSecond(ZoneOffset.UTC)));
​
    }
​
}

 

2.动态定时任务

实现SchedulingConfigurer 接口

例子

封装的一个抽象类 我们需要实现定时任务,继承该类即可

public abstract class AbsScheduleService implements SchedulingConfigurer {
​
    @Resource
    private TaskScheduler taskScheduler;
​
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.setTaskScheduler(taskScheduler);
        taskRegistrar.addTriggerTask(this::processTask, triggerContext -> {
            String cron = getCron();
            CronTrigger trigger = new CronTrigger(cron);
            // 只有一个定时任务的,不会有两个任务一同执行
            return trigger.nextExecutionTime(triggerContext);
        });
    }
​
    @Bean
    public TaskScheduler taskScheduler(){
        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
        taskScheduler.setPoolSize(2);
        taskScheduler.setAwaitTerminationSeconds(30);
        return taskScheduler;
    }
    /*
    让子类重写 主要用来获取cron表达式
    */
    public abstract String getCron();
    /*
    让子类重写 用来具体干活的方法
    */
    public abstract void processTask();
}

 

具体使用的类 可以多个 实现多个定时任务

@Component
public class TestScheduleService extends AbsScheduleService {
​
    @Resource
    private RedisTemplate<String, String> redisTemplate;
​
    @Override
    protected String getCron() {
        // 定时任务cron表达式放到数据库中
        // 可以动态修改cron表达式
        redisTemplate.opsForValue().setIfAbsent("cron", "0/5 * * * * ?");
        String cron = redisTemplate.opsForValue().get("cron");
        System.out.println("cron修改了:" + cron);
        return cron;
    }
​
    @Override
    protected void processTask() {
        try {TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}
        System.out.println("执行任务了222:" + LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
    }
}

 

 

posted @ 2022-03-31 14:45  荣超  阅读(266)  评论(0编辑  收藏  举报