zoukankan      html  css  js  c++  java
  • spring的定时任务schedule

    创建定时任务

    import com.babyeye.dao.UserDAO;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.scheduling.annotation.Scheduled;
    import org.springframework.stereotype.Service;
    
    import java.text.SimpleDateFormat;
    
    /**
     * @author Holley
     * @Description 定时任务
     * @create 2018-08-30 14:29
     **/
    @Service
    public class ScheduledTaskService {
    
        private Logger log = LoggerFactory.getLogger(ScheduledTaskService.class);
    
        private SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-DD hh:mm:ss");
    
        @Autowired
        private UserDAO userDAO;
    
        /**
          * @Author holley
          * @Description 每天早上八点将到期账号设置为已过期状态
          * @Date 2018/8/30 15:04
          * @Param []
          * @return void
          */
        @Scheduled(cron = "0 0 8 * * ?")
        public void accountOverdue(){
            userDAO.overdueAccount();
        }
    
        /**
          * @Author holley
          * @Description 延迟5秒执行一次
          * @Date 2018/8/30 15:35
          * @Param []
          * @return void
          */
        @Scheduled(fixedDelay = 5000)
        public void testFixedDelay(){
            log.info("执行fixedDelay测试方法:" + sdf.format(System.currentTimeMillis()));
        }
        /**
          * @Author holley
          * @Description 5秒执行一次
          * @Date 2018/8/30 15:36
          * @Param []
          * @return void
          */
        @Scheduled(fixedRate = 5000)
        public void testFixedRate(){
            log.info("执行fixedRate测试方法:" + sdf.format(System.currentTimeMillis()));
        }
        /**
          * @Author holley
          * @Description 第一次延迟三秒执行,之后每5秒执行一次
          * @Date 2018/8/30 15:39
          * @Param []
          * @return void
          */
        @Scheduled(initialDelay = 3000,fixedRate = 5000)
        public void testInitialDelay(){
            log.info("执行initialDelay测试方法:" + sdf.format(System.currentTimeMillis()));
        }
    
    }

    开启定时任务

    import com.babyeye.interceptor.Interceptor;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.web.servlet.ServletComponentScan;
    import org.springframework.context.annotation.Bean;
    import org.springframework.scheduling.annotation.EnableScheduling;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
    
    
    @ServletComponentScan
    @SpringBootApplication
    @EnableScheduling
    public class OkjingApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(OkjingApplication.class, args);
        }
    
    }

    下面开始介绍下secheduled的参数都有哪些:

    1.fixedDelay: 表示上一次任务执行多久后再次执行,参数类型是Long,单位毫秒

    2.fixedDelayString : 与fixedDelay含义一样,只是参数类型变成了String

    3.fixedRate : 表示按照一定的频率执行任务,参数类型是Long,单位毫秒

    4.fixedRateString : 和fixedRate含义一样,只是参数类型变成了String

    5.initialDelay : 表示延迟多久开始执行第一次任务,参数类型Long,单位毫秒

    6.initialDelayString : 与initialDelay含义一样,只是参数类型变成了String

    7.cron : cron表达式,指定任务在特定时间执行

      cron表达式定义:

        Cron表达式是一个字符串,由空格隔开的6个或7个域组成,每个域对应一个含义(秒,分,时,日,月,周 ,年),其中年是可选字段,但是spring的scheduled只支持前6个域的表达式,也就是不能设置年,如果超过则会报错

        每个域中可出现的字符类型及含义:

    (1)各域支持的字符类型

        秒:可出现", - * /"四个字符,有效范围为0-59的整数  

        分:可出现", - * /"四个字符,有效范围为0-59的整数  

        时:可出现", - * /"四个字符,有效范围为0-23的整数  

        每月第几天:可出现", - * / ? L W C"八个字符,有效范围为0-31的整数  

        月:可出现", - * /"四个字符,有效范围为1-12的整数或JAN-DEc  

        星期:可出现", - * / ? L C #"四个字符,有效范围为1-7的整数或SUN-SAT两个范围。1表示星期天,2表示星期一, 依次类推

    (2)特殊字符含义

        * : 表示匹配该域的任意值,比如在秒*, 就表示每秒都会触发事件。;

        ? : 只能用在每月第几天和星期两个域。表示不指定值,当2个子表达式其中之一被指定了值以后,为了避免冲突,需要将另一个子表达式的值设为“?”;

        - : 表示范围,例如在分域使用5-20,表示从5分到20分钟每分钟触发一次  

        / : 表示起始时间开始触发,然后每隔固定时间触发一次,例如在分域使用5/20,则意味着每小时的第5分,25分,45分,分别触发一次.  

        , : 表示列出枚举值。例如:在分域使用5,20,则意味着在5和20分时触发一次。  

        L : 表示最后,只能出现在星期和每月第几天域,如果在星期域使用1L,意味着在最后的一个星期日触发。  

        W : 表示有效工作日(周一到周五),只能出现在每月第几日域,系统将在离指定日期的最近的有效工作日触发事件。注意一点,W的最近寻找不会跨过月份  

        LW : 这两个字符可以连用,表示在某个月最后一个工作日,即最后一个星期五。  

        # : 用于确定每个月第几个星期几,只能出现在每月第几天域。例如在1#3,表示某月的第三个星期日。

       C:代表“Calendar”的意思。它的意思是计划所关联的日期,如果日期没有被关联,则相当于日历中所有日期。例如5C在日期字段中就相当于日历5日以后的第一天。1C在星期字段中相当于星期日后的第一天。

    实例:

      "0 0 * * * *"                      表示每小时0分0秒执行一次

        " */10 * * * * *"                 表示每10秒执行一次

        "0 0 8-10 * * *"                 表示每天8,9,10点执行

        "0 0/30 8-10 * * *"            表示每天8点整开始到10点,每半小时执行

        "0 0 9-17 * * 2-6"     表示每周一至周五,9点到17点的0分0秒执行

        "0 0 0 25 12 ?"                  表示每年圣诞节(12月25日)0时0分0秒执行

     8.zone : 时区,默认为当前时区,一般没有用到

    多线程执行

    不知道有没有人注意到上面代码执行结果打印出来的log,在截图中我们可以发现被执行的每个任务都是被同一个线程所调用,这是因为在pspring中如果没有自定义设置线程池时,会默认创建一个单线程的线程池。这样的话,如果定时任务增多,就会容易造成阻塞。

    如果改成多线程执行,在springboot中有两种方法。

    一。实现SchedulingConfigurer接口,重写configureTasks方法即可,代码如下:

    import org.springframework.context.annotation.Configuration;
    import org.springframework.scheduling.annotation.SchedulingConfigurer;
    import org.springframework.scheduling.config.ScheduledTaskRegistrar;
     
    import java.util.concurrent.Executors;
     
    
    @Configuration
    //所有的定时任务都放在一个线程池中,定时任务启动时使用不同都线程。
    public class ScheduleConfig implements SchedulingConfigurer {
        @Override
        public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
            //设定一个长度10的定时任务线程池
            taskRegistrar.setScheduler(Executors.newScheduledThreadPool(10));
        }
    }

    二。使用config配置类的方式添加配置,然后需要在定时任务的类或方法上添加@Async注解,代码如下:

    @Configuration // 表明该类是一个配置类
    @EnableAsync  // 开启异步支持
    public class AsyncConfig {
         /*
        此处成员变量应该使用@Value从配置中读取
         */
        private int corePoolSize = 10;
        private int maxPoolSize = 200;
        private int queueCapacity = 10;
        @Bean
        public Executor taskExecutor() {
            ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
            executor.setCorePoolSize(corePoolSize);
            executor.setMaxPoolSize(maxPoolSize);
            executor.setQueueCapacity(queueCapacity);
            executor.initialize();
            return executor;
        }
    }
    /**
     * @author Holley
     * @Description 定时任务
     * @create 2018-08-30 14:29
     **/
    @Async
    @Service
    public class ScheduledTaskService {
    
        private Logger log = LoggerFactory.getLogger(ScheduledTaskService.class);
    
        @Autowired
        private UserDAO userDAO;
    
        /**
          * @Author holley
          * @Description 每天早上八点将到期账号设置为已过期状态
          * @Date 2018/8/30 15:04
          * @Param []
          * @return void
          */
        @Scheduled(cron = "0 0 8 * * ?")
        public void accountOverdue(){
            userDAO.overdueAccount();
        }
    }

    除了上述的spring task 的scheduled之外,还有如下几种方式可以实现定时任务:

    1.Timer:java自带的java.util.Timer类,这个类允许你调度一个java.util.TimerTask任务,使用这种方式可以按照某一频率来执行,也可以设置指定时间,demo如下:

    import java.util.Date;
    import java.util.Timer;
    import java.util.TimerTask;
    
    /**
     * @author Holley
     * @Description 请输入一句话进行描述
     * @create 2018-08-31 10:45
     **/
    public class TimerDemo {
            public static void main(String[] args) {
                TimerTask timerTask = new TimerTask() {
                    @Override
                    public void run() {
                        System.out.println("task  run:"+ new Date());
                    }
                };
                Timer timer = new Timer();
                System.out.println(new Date());
                //安排指定的任务在指定的时间开始进行重复的固定延迟执行。这里是每3秒执行一次
                timer.schedule(timerTask,10000,3000);
            }
    }

    执行结果如下:

    指定时间执行:

    public class TimerTest {
    
        public static void main(String[] args) {
            Calendar calendar = Calendar.getInstance();
            /**
                * 指定触发的时间
             */
             calendar.set(Calendar.DAY_OF_MONTH,13);//设置日期为13号
             calendar.set(Calendar.MONTH, 3);//设置日期为4月份(月份是从0开始计算)
             calendar.set(Calendar.HOUR_OF_DAY, 12); //设置15点的时候触发
             calendar.set(Calendar.MINUTE, 0); //设置56分钟的时候触发
             calendar.set(Calendar.SECOND, 1); //设置第一秒的时候触发
             Date time = calendar.getTime();
             Timer timer = new Timer();
             timer.schedule(new RemindTask(), time);
        }
    }
    View Code
    public class RemindTask extends TimerTask {
        @Override
        public void run() {
            System.out.println(new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date()));
        }
    }

    详细介绍可以参考:https://blog.csdn.net/u013164931/article/details/80762356

    2.ScheduledExcutorService:也是jdk自带的一个类,是基于线程设计的定时任务,每个调度任务都会分配到线程池中的一个线程去执行,因此任务是并发执行的。demo如下:

    import java.util.Date;
    import java.util.concurrent.Executors;
    import java.util.concurrent.ScheduledExecutorService;
    import java.util.concurrent.TimeUnit;
    
    /**
     * @author Holley
     * @Description 请输入一句话进行描述
     * @create 2018-08-31 10:58
     **/
    public class ScheduleExecutorService {
        public static void main(String[] args) {
            ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
            // java8的Lambda表达式 参数:1、任务体 2、首次执行的延时时间
            //      3、任务执行间隔 4、间隔时间单位
            service.scheduleAtFixedRate(() -> System.out.println("task ScheduledExecutorService " + new Date()), 0, 3, TimeUnit.SECONDS);
        }
    }

    在此demo中使用了java8的Lambda表达式,如果对此表达式不了解的可以参考下:https://www.cnblogs.com/andywithu/p/7357069.html

     3.Quartz:这是一个功能比较强大的调度器,可以让你的程序在指定时间执行,也可以按照某一个频度执行,配置起来比较复杂,还需要添加依赖

      如果SpringBoot版本是2.0.0以后的,则在spring-boot-starter中已经包含了quart的依赖,则可以直接使用spring-boot-starter-quartz依赖:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-quartz</artifactId>
    </dependency>

      如果SpringBoot版本是1.5.9则要使用以下依赖

    <dependency>
      <groupId>org.quartz-scheduler</groupId>
      <artifactId>quartz</artifactId>
      <version>2.3.0</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context-support</artifactId>
    </dependency>
    • 创建任务类TestQuartz,该类主要是继承了QuartzJobBean
    public class TestQuartz extends QuartzJobBean {
        /**
         * 执行定时任务
         * @param jobExecutionContext
         * @throws JobExecutionException
         */
        @Override
        protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
            System.out.println("quartz task "+new Date());
        }
    }
    • 创建配置类QuartzConfig
      @Configuration
      public class QuartzConfig {
          @Bean
          public JobDetail teatQuartzDetail(){
              return JobBuilder.newJob(TestQuartz.class).withIdentity("testQuartz").storeDurably().build();
          }
      
          @Bean
          public Trigger testQuartzTrigger(){
              SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule()
                      .withIntervalInSeconds(10)  //设置时间周期单位秒
                      .repeatForever();
              return TriggerBuilder.newTrigger().forJob(teatQuartzDetail())
                      .withIdentity("testQuartz")
                      .withSchedule(scheduleBuilder)
                      .build();
          }
      }

      关于Quartz的详细内容可以查看官方文档:http://www.quartz-scheduler.org/documentation/

    参考:https://blog.csdn.net/ninifengs/article/details/77141240

          https://blog.csdn.net/wqh8522/article/details/79224290

  • 相关阅读:
    SLAM+语音机器人DIY系列:(六)SLAM建图与自主避障导航——4.多目标点导航及任务调度
    SLAM+语音机器人DIY系列:(六)SLAM建图与自主避障导航——3.ros-navigation机器人自主避障导航
    SLAM+语音机器人DIY系列:(六)SLAM建图与自主避障导航——2.google-cartographer机器人SLAM建图
    SLAM+语音机器人DIY系列:(六)SLAM建图与自主避障导航——1.在机器人上使用传感器
    SLAM+语音机器人DIY系列:(五)树莓派3开发环境搭建——7.开机自启动ROS节点
    SLAM+语音机器人DIY系列:(五)树莓派3开发环境搭建——6.树莓派USB与tty串口号绑定
    SLAM+语音机器人DIY系列:(五)树莓派3开发环境搭建——5.Android手机端与robot端ROS网络通信
    SLAM+语音机器人DIY系列:(五)树莓派3开发环境搭建——4.PC端与robot端ROS网络通信
    SLAM+语音机器人DIY系列:(五)树莓派3开发环境搭建——3.装机后一些实用软件安装和系统设置
    SLAM+语音机器人DIY系列:(五)树莓派3开发环境搭建——2.安装ros-kinetic
  • 原文地址:https://www.cnblogs.com/zhlblogs/p/9561733.html
Copyright © 2011-2022 走看看