美文网首页
补-SpringBoot 定时器(六)

补-SpringBoot 定时器(六)

作者: 3d0829501918 | 来源:发表于2022-10-19 22:05 被阅读0次

    我们先来一个谜题,一起猜一猜。

    谜题:
    小马不停蹄,日夜不休息,一阵铃儿响,催人争朝夕。 (打一常用物)文章末尾揭晓谜底。

    一、定时

        1、定时任务的适用场景

      定时任务的场景可以说非常广泛,比如某些视频网站,购买会员后,每天会给会员送成长值,每月会给会员送一些电影券;比如在保证最终一致性的场景中,往往利用定时任务调度进行一些比对工作;比如一些定时需要生成的报表、邮件;比如一些需要定时清理数据的任务等。

        2、定时任务实现的四种方式

      JDK定时类、Quartz 框架、Spring注解定时和xml配置、SpringBoot定时任务。


    二、JDK定时

      Timer是一种定时器工具,用来在一个后台线程计划执行指定任务。它可以计划执行一个任务一次或反复多次。
      TimerTask一个抽象类,它的子类代表一个可以被Timer计划的任务。具体的任务在TimerTask中run接口中实现。
      通过Timer中的schedule方法启动定时任务。

        1、在指定日期运行定时器任务,只运行一次

    public static void main(String[] args) throws ParseException {
        String sdate = "2018-02-14";
        SimpleDateFormat sf = new SimpleDateFormat("yy-MM-dd");
        Date date = sf.parse(sdate);
    
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
    
            @Override
            public void run() {
                System.out.println("系统正在运行……");
            }
        }, date); //在指定的日期运行一次定时任务
       /*如果date日期在今天之前,则启动定时器后,立即运行一次定时任务run方法*/
       /*如果date日期在今天之后,则启动定时器后,会在指定的将来日期运行一次任务run方法*/
    }
    

        2、在距当前时刻的一段时间后运行定时器任务,只运行一次

    public static void main(String[] args) {
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
    
            @Override
            public void run() {
                System.out.println("系统正在运行……");
            }
        }, 5000); //指定启动定时器5s之后运行定时器任务run方法,并且只运行一次
    }
    

        3、在指定的时间后,每隔指定的时间,重复运行定时器任务

    public static void main(String[] args) throws ParseException {
        String sdate = "2018-02-10";
        SimpleDateFormat sf = new SimpleDateFormat("yy-MM-dd");
        Date date = sf.parse(sdate);
    
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
    
            @Override
            public void run() {
                System.out.println("系统正在运行……");
            }
        }, date, 2000);
        /*如果指定的date时间是当天或者今天之前,启动定时器后会立即每隔2s运行一次定时器任务*/
        /*如果指定的date时间是未来的某天,启动定时器后会在未来的那天开始,每隔2s执行一次定时器任务*/
    }
    

        4、在距当前时刻的一段指定距离后,每隔指定时间运行一次定时器任务

    public static void main(String[] args) {
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
    
            @Override
            public void run() {
                System.out.println("系统正在运行……");
            }
        }, 5000, 2000);
        /*当启动定时器后,5s之后开始每隔2s执行一次定时器任务*/
    }
    

    停止定时器的四种方式
      1、调用Timer的cancel方法;
      2、把Timer线程设置成Daemon守护线程,当所有的用户线程结束后,那么守护线程也会被终止;
      3、当所有的任务执行结束后,删除对应Timer对象的引用,线程也会被终止;
      4、调用System.exit方法终止程序


    三、Quartz

      Quartz是一个完全由Java编写的开源作业调度框架,为在Java应用程序中进行作业调度提供了简单却强大的机制。
        1、pom文件

      <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>2.3.0</version>
        </dependency>
    

        2、实现job接口在execute方法写相关业务

    public class TestJob implements Job {
    
        private Logger logger = LoggerFactory.getLogger(TestJob.class);
    
        @Override
        public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
             System.out.println("业务写在这里");
             logger.info(Thread.currentThread().getName() + " test job begin " + new Date());
        }
    }
    

        3、测试类

    public static void main(String[] args) throws InterruptedException, SchedulerException {
    
        Scheduler scheduler = new StdSchedulerFactory().getScheduler();
        // 开始
        scheduler.start();
        // job 唯一标识 test.test-1
        JobKey jobKey = new JobKey("test" , "test-1");
        JobDetail jobDetail = JobBuilder.newJob(TestJob.class).withIdentity(jobKey).build();
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("test" , "test")
                // 延迟一秒执行
                .startAt(new Date(System.currentTimeMillis() + 1000))
                // 每隔一秒执行 并一直重复
                .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(1).repeatForever())
                .build();
        scheduler.scheduleJob(jobDetail , trigger);
        Thread.sleep(5000);
        // 删除job
        scheduler.deleteJob(jobKey);
    }
    
    public static void main(String[] args) throws InterruptedException, SchedulerException {
    
        Scheduler scheduler = new StdSchedulerFactory().getScheduler();
        // 开始
        scheduler.start();
        // job 唯一标识 test.test-1
        JobKey jobKey = new JobKey("test" , "test-1");
        JobDetail jobDetail = JobBuilder.newJob(TestJob.class).withIdentity(jobKey).build();
        // 可以设置定时任务具体时间
        CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity("test", "test-1").withSchedule(
                CronScheduleBuilder.cronSchedule("/2 * * * * ?")
        ).build();
        scheduler.scheduleJob(jobDetail , trigger);
        Thread.sleep(5000);
        // 删除job
        scheduler.deleteJob(jobKey);
    }
    

    四、Spring定时

        1、注解版本

    <task:annotation-driven />
    配置扫描任务位置
    <!-- 扫描任务 -->
    <context:component-scan base-package="com.vrveis.roundTrip.task" />
    
    package com.vrveis.roundTrip.task;
    import org.springframework.scheduling.annotation.Scheduled;
    import org.springframework.stereotype.Component;
    
    @Component
    public class FlightTrainTask {
    
        @Scheduled(cron = "0/5 * * * * ? ") // 间隔5秒执行
        public void taskCycle() {
            System.out.println("使用Spring框架配置定时任务");
        }
    }
    

        2、Xml版本

    <context:component-scan base-package="com" />
    <!-- spring框架的Scheduled定时器 -->
    <task:scheduled-tasks>
        <task:scheduled ref="springTiming" method="test" cron="0 0 12 * * ?"/>
    </task:scheduled-tasks>
    
    
    public class SpringTiming {
    
          public void test(){ 
               System.out.println("使用Spring定时任务");
          }
    }
    

    五、SpringBoot实现定时

        1、pom文件

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <optional>true</optional>
    </dependency>
    

        2、启动类添加@EnableScheduling 注解

     @SpringBootApplication
     @EnableScheduling
     public class Application {
    
             public static void main(String[] args) {
                   SpringApplication.run(Application.class, args);
             }
    }
    

        3、创建定时任务类

    @Component
    public class SchedulerTask {
    
    
           private Logger logger = LoggerFactory.getLogger(SchedulerTask.class);
    
           private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
    
           private int count = 0;
    
           @Scheduled(cron="*/6 * * * * ?")
           private void process(){
                  logger.info("this is scheduler task runing  "+(count++));
           }
    
           @Scheduled(fixedRate = 6000)
           public void reportCurrentTime() {
                  logger.info("现在时间:" + dateFormat.format(new Date()));
           }
    }
    

        4、运行结果

    2019-01-19 14:49:12.025  INFO 17024 --- [pool-1-thread-1] 
    c.example.springbootdemo.SchedulerTask   : this is scheduler task runing  0
    2019-01-19 14:49:13.109  INFO 17024 --- [pool-1-thread-1] 
    c.example.springbootdemo.SchedulerTask   : 现在时间:14:49:13
    

    通过运行结果看到是一个线程执行定时任务,如果在同一时间启动多个定时器怎么办?

    增加一个配置类

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

    测试结果可以看出现在是多个线程运行定时器。

     2019-01-19 14:51:30.025  INFO 18392 --- [pool-1-thread-2] 
     c.example.springbootdemo.SchedulerTask   : this is scheduler task runing  0
     2019-01-19 14:51:32.214  INFO 18392 --- [pool-1-thread-1] 
     c.example.springbootdemo.SchedulerTask   : 现在时间:14:51:32
    

    Cron表达式

    corn从左到右(用空格隔开):秒 分 小时 月份中的日期 月份 星期中的日期 年份


    相关文章

      网友评论

          本文标题:补-SpringBoot 定时器(六)

          本文链接:https://www.haomeiwen.com/subject/wfsyzrtx.html