• 解决crontab定时任务只能按照固定时间开始执行,不能实现立即执行的问题


    import org.quartz.TriggerUtils;
    import org.quartz.impl.triggers.CronTriggerImpl;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.scheduling.Trigger;
    import org.springframework.scheduling.TriggerContext;
    import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
    import org.springframework.scheduling.config.CronTask;
    
    import java.text.ParseException;
    import java.time.Duration;
    import java.util.Date;
    import java.util.List;
    import java.util.concurrent.atomic.AtomicLong;
    
    /**
     *  所用依赖:
     *     <dependencies>
     *         <dependency>
     *             <groupId>org.springframework.boot</groupId>
     *             <artifactId>spring-boot-starter-web</artifactId>
     *             <version>2.1.8.RELEASE</version>
     *         </dependency>
     *         <dependency>
     *             <groupId>org.quartz-scheduler</groupId>
     *             <artifactId>quartz</artifactId>
     *             <version>2.3.2</version>
     *         </dependency>
     *     </dependencies>
     */
    
    /**
     * 解决crontab定时任务只能按照固定时间开始执行,不能实现立即执行的问题。
     * 问题描述:
     **  1. crontab表达式比如 0 0/10 * * * ?
     *   2. 当前时间是2021-07-20 17:58:00, 那么它接下来的执行时间
     *      只能是
     *          2021-07-20 18:00:00
     *          2021-07-20 18:10:00
     *          2021-07-20 18:20:00
     *          2021-07-20 18:30:00
     *      而无法是
     *          2021-07-20 17:58:00(第一次为立即执行)
     *          2021-07-20 18:08:00
     *          2021-07-20 18:18:00
     *          2021-07-20 18:28:00
     *   3. 这篇提供的代码能做到 执行时间为
     *          2021-07-20 17:58:00(第一次为立即执行)
     *          2021-07-20 18:10:00(第二次会根据周期间隔做修正,注意这里跳过了2021-07-20 18:00:00这个时刻)
     *          2021-07-20 18:20:00
     *          2021-07-20 18:30:00
     *      "根据周期间隔做修正"的意思就是说,假如当前时间是2021-07-20 17:52:00,那么执行时间就是
     *          2021-07-20 17:52:00(第一次为立即执行)
     *          2021-07-20 18:00:00(这一次就没有跳过18:00这个时刻)
     *          2021-07-20 18:10:00
     *          2021-07-20 18:20:00
     *          2021-07-20 18:30:00
     *
     */
    @SpringBootApplication
    public class Main {
        public static void main(String[] args) {
            SpringApplication.run(Main.class, args);
    
            System.out.println(new Date());
    
            Task task = new Task();
            task.start();
    
        }
    }
    
    class Task{
        public void start() {
            String cron = "0 */1 * * * ?";
            ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
            taskScheduler.setPoolSize(1);
            taskScheduler.initialize();
            CronTask discoverTask = new CronTask(new Executor(), cron);
            Trigger tmp = discoverTask.getTrigger();
    
            CronTriggerImpl cronTriggerImpl = new CronTriggerImpl();
            try {
                cronTriggerImpl.setCronExpression(cron);
            } catch (ParseException e) {
                e.printStackTrace();
            }
            List<Date> dates = TriggerUtils.computeFireTimes(cronTriggerImpl, null, 3);
            for (int i = 0; i < dates.size(); i++) {
                System.out.println("接下来第" + (i + 1) + "次执行时间" + dates.get(i));
            }
            Duration between = Duration.between(dates.get(0).toInstant(), dates.get(1).toInstant()).abs();
            long step = between.getSeconds();
            if (step == 0) {
                step = 1;
            }
            System.out.println("执行周期为" + step + "秒");
    
            long finalStep = step;
            Trigger trigger = new Trigger() {
                AtomicLong count = new AtomicLong(1);
                double factor = 0.75; // 调节因子
                Date firstRunDate;
    
                @Override
                public Date nextExecutionTime(TriggerContext triggerContext) {
                    if (count.get() == 1) { // 第一次用当前时间作为触发时间
                        firstRunDate = new Date();
                        count.incrementAndGet();
                        return firstRunDate;
                    }
                    if (count.get() == 2) {  // 第二次判断是否如期执行。如果该次时间和第一次执行时间"很近", 就忽略该次。
                        Date current = tmp.nextExecutionTime(triggerContext);
                        long past = Duration.between(firstRunDate.toInstant(), current.toInstant()).abs().getSeconds();
                        count.incrementAndGet();
                        if (past > (factor * finalStep)) {
                            System.out.println("第一次执行时间距下一次执行时间间隔" + past + "秒, 接近一个周期,run!");
                            return current;
                        }
                        System.out.println("第一次执行时间距下一次执行时间间隔" + past + "秒, 间隔太短,不run!");
                        return null;
                    }
                    return tmp.nextExecutionTime(triggerContext);
                }
            };
            taskScheduler.schedule(discoverTask.getRunnable(), trigger);
        }
    
        public class Executor implements Runnable {
            @Override
            public void run() {
                System.out.println("运行中,当前时间:" + new Date());
            }
        }
    }
  • 相关阅读:
    javascript语句语义大全(6)
    javascript语句语义大全(5)
    javascript语句语义大全(4)
    javascript语句语义大全(3)
    javascript语句语义大全(2)
    javascript语句语义大全(1)
    javascript基础知识(1)
    模版引擎Handlebars语法(1)
    一个完整的项目中,需要的基本gulp
    HTML5新特性总览
  • 原文地址:https://www.cnblogs.com/simuhunluo/p/15036302.html
Copyright © 2020-2023  润新知