zoukankan      html  css  js  c++  java
  • Java 定时任务调度(3)--Spring Scheduled 介绍

    Spring 提供了@Scheduled 注解,可用比较便捷的解决定时任务的需求,它的内部实现是基于 java 中的 ScheduledThreadPoolExecutor 类。本文主要介绍 Spring Boot 环境下 @Scheduled 的使用;文中所使用到的软件版本:Spring Boot 2.4.4、jdk1.8.0_181。

    1、@Scheduled简介

    @Scheduled 注解标注在方法上,可以支持如下几种方式运行:
    1.@Scheduled(fixedRate = 3000) 按固定时间间隔运行
    2.@Scheduled(fixedDelay = 3000) 上一次任务运行完成后等待固定时间运行下一次任务
    3.@Scheduled(cron = "0 0/1 * * * ?") 按照 cron 表达式定义的时间方式运行

    2、Spring Boot 环境下 @Scheduled 使用

    2.1、启动类上添加 @EnableScheduling 注解

    @EnableScheduling
    @SpringBootApplication
    @ComponentScan(basePackages = {"com.abc"})
    public class DemoApplication {
        public static void main(String[] args) {
            SpringApplication.run(DemoApplication.class, args);
        }
    }

    2.2、设置任务线程池大小

    默认任务线程池大小为 1,如想修改,可在 application.yml 中添加如下配置:

    spring:
      task:
        scheduling:
          pool:
            size: 10

    2.3、使用例子

    package com.abc.demo.task;
    
    import com.abc.demo.util.JwtUtil;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.scheduling.annotation.Scheduled;
    import org.springframework.stereotype.Component;
    
    @Component
    public class TestTask {
        private static Logger logger = LoggerFactory.getLogger(JwtUtil.class);
    
        @Scheduled(cron = "0 0/1 * * * ?")
        private void test1() {
            logger.info("cron表达式");
        }
    
        @Scheduled(initialDelay = 2000, fixedRate = 3000)
        private void test2() {
            logger.info("延迟2s运行第一次,然后每隔3s运行一次");
        }
    
        @Scheduled(initialDelay = 3000, fixedDelay = 4000)
        private void test3() {
            logger.info("延迟3s运行第一次,上一次任务运行结束后等4s再运行下一次任务。");
        }
    }

    2.4、动态启动、停止定时任务

    假设需要在页面动态的添加并保存定时任务到数据库,添加完成后可以在页面启动或停止该任务;可以编写一个 Controller 来实现该功能。

    package com.abc.demo.controller;
    
    import com.abc.demo.entity.R;
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.scheduling.TaskScheduler;
    import org.springframework.scheduling.support.CronTrigger;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import javax.annotation.PostConstruct;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.concurrent.ConcurrentHashMap;
    import java.util.concurrent.ScheduledFuture;
    
    /**
     * 这里只涉及任务的启动,停止,重启
     *
     * 任务的新增、修改、删除可以编写方法实现,任务数据保存在数据库里
     */
    @RequestMapping("/schedule")
    @RestController
    public class ScheduleController {
        private static Logger logger = LoggerFactory.getLogger(StudentController.class);
    
        private static Map<Integer, ScheduledFuture> futures = new ConcurrentHashMap<>();
    
        //模拟数据库的任务配置数据
        private Map<Integer, TaskConfig> taskConfigs = new HashMap(){{
            put(1, new TaskConfig(1, "任务1", "0/5 * * * * *"));
            put(2, new TaskConfig(2, "任务2", "0/6 * * * * *"));
            put(3, new TaskConfig(3, "任务3", "0/7 * * * * *"));
            put(4, new TaskConfig(4, "任务4", "0/8 * * * * *"));
            put(5, new TaskConfig(5, "任务5", "0/9 * * * * *"));
        }};
    
        @Autowired
        private TaskScheduler taskScheduler;
    
        /**程序启动时,启动所有任务*/
        @PostConstruct
        private void init() {
            for (Map.Entry<Integer, TaskConfig> entry : taskConfigs.entrySet()) {
                TaskConfig taskConfig = entry.getValue();
                ScheduledFuture<?> future = taskScheduler.schedule(new MyRunnable(taskConfig.getBussinessParam()), new CronTrigger(taskConfig.getCron()));
                futures.put(entry.getKey(), future);
            }
        }
    
        @RequestMapping("/startTask")
        public R<String> startTask(Integer taskId) {
            ScheduledFuture<?> future = futures.get(taskId);
            if (future == null) {
                TaskConfig taskConfig = taskConfigs.get(taskId);
                future = taskScheduler.schedule(new MyRunnable(taskConfig.getBussinessParam()), new CronTrigger(taskConfig.getCron()));
                futures.put(taskId, future);
            } else {
                logger.info("任务已启动");
            }
            return R.ok();
        }
    
        @RequestMapping("/stopTask")
        public R<String> stopTask(Integer taskId) {
            ScheduledFuture<?> future = futures.get(taskId);
            if (future != null) {
                future.cancel(true);
                futures.remove(taskId);
            } else {
                logger.info("任务已停止");
            }
            return R.ok();
        }
    
        @RequestMapping("/restartTask")
        public R<String> restartTask(Integer taskId) {
            ScheduledFuture<?> future = futures.get(taskId);
            if (future == null) {
                TaskConfig taskConfig = taskConfigs.get(taskId);
                future = taskScheduler.schedule(new MyRunnable(taskConfig.getBussinessParam()), new CronTrigger(taskConfig.getCron()));
                futures.put(taskId, future);
            } else {
                future.cancel(true);
                TaskConfig taskConfig = taskConfigs.get(taskId);
                future = taskScheduler.schedule(new MyRunnable(taskConfig.getBussinessParam()), new CronTrigger(taskConfig.getCron()));
                futures.put(taskId, future);
            }
            return R.ok();
        }
    
        class MyRunnable implements Runnable {
            private String param;
            public MyRunnable(String param) {
                this.param = param;
            }
    
            @Override
            public void run() {
                logger.info("MyRunnable:{}", param);
            }
        }
    
        @Data
        @AllArgsConstructor
        class TaskConfig {
            /**主键*/
            private Integer id;
    
            /**业务参数*/
            private String bussinessParam;
    
            /**cron表达式*/
            private String cron;
        }
    }
  • 相关阅读:
    (unix domain socket)使用udp发送>=128K的消息会报ENOBUFS的错误
    HTTP KeepAlive模式
    Windows 7 中的 God Mode
    我的开发环境配置经验
    C#格式化数值结果表(格式化字符串)
    我可怜的笔记本电脑
    JetBrains ReSharper 5.x 注册机
    异常处理准则
    调用 Windows 7 中英文混合朗读
    oracle笔记(2010130)
  • 原文地址:https://www.cnblogs.com/wuyongyin/p/14721248.html
Copyright © 2011-2022 走看看