乐趣区

关于java:SpringBoot进阶之道Scheduled


很多小伙伴在理论开发中,肯定碰到过须要定时去执行某些业务逻辑的时候,解决方案有很多,比方 Saturn、ElasticJob、MQ 等。不过在这里博主介绍的是 springboot 提供的比拟好用的定时工作组件 Scheduled。

大家都晓得 spring 创立定时工作 so esay,上面有三种形式:

  • 基于注解 (@Scheduled)
  • 基于接口 (SchedulingConfigurer)
  • 基于注解设定多线程定时工作

一、基于注解 (@Scheduled)

须要留神的是 @Scheduled 默认是串行的,单线程,当开启多个工作时,工作的执行时机会受上一个工作执行工夫的影响。

@Configuration
@EnableScheduling    // 开启定时工作
public class ScheduleTask {
    // 每 10 秒执行一次
    @Scheduled(cron = "0/10 * * * * ?")
    private void configureTasks() {System.out.println("我是一个定时工作");
    }
}

@Scheduled 除了 cron 还提供另外三种种形式: fixedRate,fixedDelay,initialDelay
1、cron 表达式能够定制化执行工作,然而执行的形式是与 fixedDelay 相近的,也是会依照上一次办法完结工夫开始算起。
2、fixedDelay 管制办法执行的间隔时间,是以上一次办法执行完开始算起,如上一次办法执行阻塞住了,那么直到上一次执行完,并距离给定的工夫后,执行下一次。

@Configuration
@EnableScheduling    // 开启定时工作
public class ScheduleTask {
    // 每 10 秒执行一次
    @Scheduled(fixedDelay = 10000)
    private void configureTasks() {System.out.println("我是一个定时工作");
    }
}

3、fixedRate 是依照肯定的速率执行,是从上一次办法执行开始的工夫算起,如果上一次办法阻塞住了,下一次也是不会执行,然而在阻塞这段时间内累计应该执行的次数,当不再阻塞时,一下子把这些全副执行掉,而后再依照固定速率继续执行。

@Configuration
@EnableScheduling    // 开启定时工作
public class ScheduleTask {
    // 每 10 秒执行一次
    @Scheduled(fixedRate = 10000)
    private void configureTasks() {System.out.println("我是一个定时工作");
    }
}

4、initialDelay = 10000 示意在容器启动后,提早 10 秒后再执行一次定时器。

@Configuration
@EnableScheduling    // 开启定时工作
public class ScheduleTask {
    // 容器启动后, 提早 10 秒后再执行一次定时器, 当前每 10 秒再执行一次该定时器。@Scheduled(initialDelay = 10000, fixedRate = 10000)
    private void configureTasks() {System.out.println("我是一个定时工作");
    }
}

二、基于接口 (SchedulingConfigurer)

有些小猿可能发现,应用 @Scheduled 注解很不便,但毛病是当咱们调整了执行周期的时候,须要重启利用能力失效,这多少有些不不便。为了达到实时失效的成果,那么能够应用接口来实现定时工作。

  • 上面案例从数据中获取执行周期时间,而后动静执行定时工作:
@Configuration      
@EnableScheduling   // 开启定时工作
public class DynamicScheduleTask implements SchedulingConfigurer {

    // 从数据获取工作执行周期
    @Autowired
    private MyBatisMapper myBatisMapper;

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.addTriggerTask(//1. 增加工作内容 (Runnable)
                () -> System.out.println("执行动静定时工作:" + LocalDateTime.now().toLocalTime()),
                //2. 设置执行周期 (Trigger)
                triggerContext -> {
                    //2.1 从数据库获取执行周期
                    String cron = myBatisMapper.getCron();
                    //2.2 返回执行周期 (Date)
                    return new CronTrigger(cron).nextExecutionTime(triggerContext);
                }
        );
    }
}

数据库表数据如下:

好,咱们启动测试看看

 执行动静定时工作: 17:17:00.008999
执行动静定时工作: 17:17:20.002501
执行动静定时工作: 17:17:30.001786
执行动静定时工作: 17:17:40.005512
执行动静定时工作: 17:17:50.005870
执行动静定时工作: 17:18:00.002189
执行动静定时工作: 17:18:10.001910

咱们能够看到每 10 秒执行一次工作。那么当初要求每 5 秒执行一次,该怎么做呢?这个时候咱们只须要批改下数据库数据即可,无需重启。

OK,咱们再看看控制台打印的是什么?

 执行动静定时工作: 17:18:30.000902
执行动静定时工作: 17:18:40.001392
执行动静定时工作: 17:18:45.005027
执行动静定时工作: 17:18:50.001367
执行动静定时工作: 17:18:55.001356
执行动静定时工作: 17:19:00.001582
执行动静定时工作: 17:19:05.005676
执行动静定时工作: 17:19:10.001258
执行动静定时工作: 17:19:15.005272

胜利每 5 秒执行一次。是不是很嗨~

三、基于注解设定多线程定时工作

后面讲到了 @Scheduled 执行周期工作会受到上次一个工作的执行工夫影响。那么能够开启多线程执行周期工作。

@EnableScheduling   // 1. 开启定时工作
@EnableAsync        // 2. 开启多线程
@Component
public class MultiThreadScheduleTask {

    @Async
    @Scheduled(fixedDelay = 1000)  // 距离 1 秒
    public void first() throws InterruptedException {System.out.println("第一个定时工作开始 :" + LocalDateTime.now().toLocalTime() + "\r\n 线程 :" + Thread.currentThread().getName());
        Thread.sleep(1000 * 10);
    }

    @Async
    @Scheduled(fixedDelay = 2000)
    public void second() {System.out.println("第二个定时工作开始 :" + LocalDateTime.now().toLocalTime() + "\r\n 线程 :" + Thread.currentThread().getName());
    }
}

咱们重启下我的项目看看控制台输入什么:

 第二个定时工作开始 : 17:27:01.024288
线程 : task-4
第一个定时工作开始 : 17:27:01.024393
线程 : task-7
第一个定时工作开始 : 17:27:02.027932
线程 : task-4
第二个定时工作开始 : 17:27:05.021294
线程 : task-1
第一个定时工作开始 : 17:27:05.021533
线程 : task-1
第一个定时工作开始 : 17:27:06.014213

看,因为开启了多线程,第一个工作的执行工夫也不受其自身执行工夫的限度。两个工作也互不影响。

退出移动版