• SpringBoot(十三):springboot2.0.2定时任务


    使用定义任务:

    第一步:启用定时任务
    第二步:配置定时器资源等
    第三步:定义定时任务并指定触发规则

    1)启动类启用定时任务

    在springboot入口类上添加注解@EnableScheduling即可。

    @SpringBootApplication(scanBasePackages = {})
    @MapperScan("com.dx.jobmonitor.mapper")
    @EnableScheduling
    public class App {
        private static final Logger logger = LoggerFactory.getLogger(App.class);
    
        public static void main(String[] args) {
            logger.info("App start...");
            SpringApplication.run(App.class, args);
        }
    }

    2)配置定时任务资源等:

    设置定时任务线程池大小:通过SchedulingConfigurer接口配置并行方式
    当定时任务很多的时候,为了提高任务执行效率,可以采用并行方式执行定时任务,任务之间互不影响,只要实现SchedulingConfigurer接口就可以。

    /**
     * 配置定时任务<br>
     * 1)当定时任务很多的时候,为了提高任务执行效率,可以采用并行方式执行定时任务,任务之间互不影响,只要实现SchedulingConfigurer接口就可以。<br>
     * 2)这里指定用3个线程来并行处理
     * **/
    @Configuration
    public class ScheduledConfig implements SchedulingConfigurer {
        @Override
        public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
            scheduledTaskRegistrar.setScheduler(setTaskExecutors());
        }
    
        @Bean(destroyMethod = "shutdown")
        public Executor setTaskExecutors() {
            return Executors.newScheduledThreadPool(3);
        }
    }


    在并行执行的时候,创建线程池采用了newScheduledThreadPool这个线程池。
    Executors框架中存在几种线程池的创建线程池的采用的队列是延迟队列:

    •     newCachedThreadPool() ,
    •     newFixedThreadPool(),
    •     newSingleThreadExecutor(),
    •     newScheduledThreadPool()。

    newScheduledThreadPool() 线程池的特性是定时任务能够定时或者周期性的执行任务。

    public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue());
    }

    其中线程池核心线程数是自己设定的,最大线程数是最大值。阻塞队列是自定义的延迟队列:DelayedWorkQueue()

    3)定义定时任务

    定时任务1:

    @Component
    public class SchedulerTask {
        private int count=0;
    
        @Scheduled(cron="*/6 * * * * ?")
        private void process(){
            System.out.println("this is scheduler task runing  "+(count++));
        }
    }

    定时任务2:

    从application.yml中读取cron参数

    @Component
    public class Scheduler2Task {
        private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
    
        @Scheduled("jobs.scheduled.cron")
        public void reportCurrentTime() {
            System.out.println("现在时间:" + dateFormat.format(new Date()));
        }
    }

    此时application.yml中配置信息如下:

    jobs:
      scheduled:
        cron: 0/30 * * * * ?

    参数说明:
      @Scheduled接受两种定时的设置:

    1. 一种是cornexpression。
    2. 一种是Rate/Delay表达式(毫秒值):
    • @Scheduled(fixedRate = 6000):上一次开始执行时间点后每隔6秒执行一次。
    • @Scheduled(fixedDelay = 6000):上一次执行完毕时间点之后6秒再执行。
    • @Scheduled(initialDelay=1000, fixedRate=6000):第一次延迟1秒后执行,之后按fixedRate的规则每6秒执行一次。

    动态修改scheduled的cron参数:

    动态修改定时任务cron参数时:

    • 1)不需要重启应用就可以动态的改变Cron表达式的值
    • 2)不能使用@Scheduled(cron = “${jobs.cron}”)实现
    @Component
    public class SpringDynamicCronTask implements SchedulingConfigurer {
        private static final Logger logger = LoggerFactory.getLogger(SpringDynamicCronTask.class);
        private static String cron = "0/5 * * * * ?";
    
        @Autowired
        private TaskDynamicCronService taskCronService;
        
        @Override
        public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
            scheduledTaskRegistrar.addTriggerTask(() -> {
                // 任务逻辑
                logger.error("dynamicCronTask is running...");
            }, triggerContext -> {
                // 任务触发,在这里可修改任务的执行周期,因为每次调度都会执行这里
                // 1)这里可以修改为从数据读取cron
                // cron=taskCronService.getCron();
                CronTrigger cronTrigger = new CronTrigger(cron);
                return cronTrigger.nextExecutionTime(triggerContext);
            });
        }
    
        /**
        * 2) 供应用端调用动态修改cron参数方法
        * @Controller
        * @RequestMapping("/cron")")
        * public class CronController{
        *        @Autowired
        *        private SpringDynamicCronTask cronTask;
        *
        *         @PostMapping("/update")
        *        @ResponseBody
        *        public String update(String cron) {
        *            cronTask.setCron(cron);
        *        }
        * }
        */ 
        public void setCron(String cron) {
             this.cron=cron;
        }
    }

    动态设置cron参数常用方式包含两种:

    1)动态查询并设置cron

    定义CronTrigger时,从数据库中动态查询cron并设置

        @Autowired
        private TaskDynamicCronService taskCronService;
        
        @Override
        public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
            scheduledTaskRegistrar.addTriggerTask(() -> {
                // 任务逻辑
                logger.error("dynamicCronTask is running...");
            }, triggerContext -> {
                cron=taskCronService.getCron();
                CronTrigger cronTrigger = new CronTrigger(cron);
                return cronTrigger.nextExecutionTime(triggerContext);
            });
        }

    2)通过接口函数修改cron值

    SpringDynamicCronTask 类,提供修改cron函数setCron()。

    @Component
    public class SpringDynamicCronTask implements SchedulingConfigurer {
        private static final Logger logger = LoggerFactory.getLogger(SpringDynamicCronTask.class);
        private static String cron = "0/5 * * * * ?";
        @Override
        public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
            scheduledTaskRegistrar.addTriggerTask(() -> {
                // 任务逻辑
                logger.error("dynamicCronTask is running...");
            }, triggerContext -> {
                CronTrigger cronTrigger = new CronTrigger(cron);
                return cronTrigger.nextExecutionTime(triggerContext);
            });
        }
    
        /**
        * 供应用端调用动态修改cron参数方法
        */ 
        public void setCron(String cron) {
             this.cron=cron;
        }
    }

    应用端调用:

    @Controller
    @RequestMapping("/cron")")
    public class CronController{
            @Autowired
            private SpringDynamicCronTask cronTask;
    
            @PostMapping("/update")
            @ResponseBody
            public String update(String cron) {
               cronTask.setCron(cron);
            }
    }

    多定时任务管理

    定义多定时任务管理类

    class BatchTaskSchedule {
        private ThreadPoolTaskScheduler executor = new ThreadPoolTaskScheduler();
        private ScheduledFuture<?> future;
        private Integer key;
    
        public BatchTaskSchedule(Integer key) {
            this.key = key;
        }
    
        public void start() {
            executor.setPoolSize(1);
            executor.setThreadNamePrefix("taskExecutor-");
            executor.setWaitForTasksToCompleteOnShutdown(true);
            executor.setAwaitTerminationSeconds(60);
            // 必须得先初始化,才能使用
            executor.initialize();
            future = executor.schedule(new Runnable() {
                @Override
                public void run() {
                    System.out.println("[" + Thread.currentThread().getName() + "-" + key + "]Hello "
                            + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
                }
            }, new CronTrigger("0/15 * * * * ?"));
        }
    
        public void restart() {
            // 先停止,在开启.
            stop();
            start();
        }
    
        public void stop() {
            if (future != null) {
                future.cancel(true);
            }
        }
    }

    使用测试示例:

    @RunWith(SpringJUnit4ClassRunner.class)
    @SpringBootTest(classes = { App.class }, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
    public class CommonTest {
        // 定时任务存储集合:当需要停止、重启任务时,可以从该集合中获取待操作任务。
        private static Map<Integer, BatchTaskSchedule> taskBack = new HashMap<Integer, BatchTaskSchedule>();
    
        @Test
        public void test() {
            for (int i = 0; i < 2; i++) {
                // 创建定时任务
                BatchTaskSchedule taskScheduled = new BatchTaskSchedule(i);
                taskScheduled.start();
                taskBack.put(i, taskScheduled);
            }
    
            try {
                Thread.sleep(1 * 60 * 1000);
                // 停止掉某个任务
                taskBack.get(0).stop();
                Thread.sleep(1 * 60 * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
  • 相关阅读:
    HTTP 无法注册URL 进程不具有命名空间的访问权限
    逆变与协变详解
    正式学习React(五) react-redux源码分析
    正式学习React(四) ----Redux源码分析
    正式学习react(二)
    工作总结
    如何自定义echarts 线性图的选择事件
    viewport大白话
    关于div可编辑的复制粘贴问题
    nginx学习
  • 原文地址:https://www.cnblogs.com/yy3b2007com/p/10483522.html
Copyright © 2020-2023  润新知