Springboot2(19)定时任务

1) Java自带的java.util.Timer类,这个类允许你调度一个java.util.TimerTask任务。 最早的时候就是这样写定时任务的。

2) 开源的第三方框架: Quartz 或者 elastic-job , 但是这个比较复杂和重量级,适用于分布式场景下的定时任务,可以根据需要多实例部署定时任务。

3) 使用Spring提供的注解: @Schedule 。 如果定时任务执行时间较短,并且比较单一,可以使用这个注解。

@Scheduled

串行方式

使用的注解: @Scheduled@EnableScheduling

一般

@Slf4j
@Component
@EnableScheduling
public class ScheduleTask {
    @Scheduled(cron = "0/2 * * * * ?")
    public void task() throws InterruptedException {
        log.info("执行定时任务1");
        Thread.sleep(60000);
    }
​
    @Scheduled(cron = "0/2 * * * * ?")
    public void task2() throws InterruptedException {
        log.info("执行定时任务2");
        Thread.sleep(5000);
    }
}

@EnableScheduling添加在启动类中

结果

2018-12-21 15:25:56.000  INFO 4864 --- [   scheduling-1]   : 执行定时任务1
2018-12-21 15:26:56.001  INFO 4864 --- [   scheduling-1]   : 执行定时任务2
2018-12-21 15:27:01.002  INFO 4864 --- [   scheduling-1]   : 执行定时任务1
2018-12-21 15:28:01.002  INFO 4864 --- [   scheduling-1]   : 执行定时任务2


可以看出两个定时任务时互斥的,同一时间只有定时任务在执行。

并行方式

当定时任务很多的时候,为了提高任务执行效率,可以采用并行方式执行定时任务,任务之间互不影响,  只要实现SchedulingConfigurer接口就可以

@Configuration
public class ScheduledConfig  implements SchedulingConfigurer {
    @Override
    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
        scheduledTaskRegistrar.setScheduler(setTaskExecutors());
    }
    @Bean
    public Executor setTaskExecutors(){
        return Executors.newScheduledThreadPool(3); // 3个线程来处理。
    }
}

结果

2018-12-21 15:34:02.002  INFO 2984 --- [pool-1-thread-1]   : 执行定时任务1
2018-12-21 15:34:02.002  INFO 2984 --- [pool-1-thread-2]   : 执行定时任务2
2018-12-21 15:34:08.002  INFO 2984 --- [pool-1-thread-2]   : 执行定时任务2
2018-12-21 15:34:14.000  INFO 2984 --- [pool-1-thread-2]   : 执行定时任务2
2018-12-21 15:34:20.001  INFO 2984 --- [pool-1-thread-3]   : 执行定时任务2
2018-12-21 15:34:26.001  INFO 2984 --- [pool-1-thread-3]   : 执行定时任务2


cron表达式

cron一共有7位,但是最后一位是年,可以留空,所以我们可以写6位

  • 第一位,表示秒,取值0-59

  • 第二位,表示分,取值0-59

  • 第三位,表示小时,取值0-23

  • 第四位,日期天/日,取值1-31

  • 第五位,日期月份,取值1-12

  • 第六位,星期,取值1-7,星期一,星期二...,注:不是第1周,第二周的意思 另外:1表示星期天,2表示星期一。

  • 第7为,年份,可以留空,取值1970-2099

cron中,还有一些特殊的符号,含义如下

  • (*)星号:可以理解为每的意思,每秒,每分,每天,每月,每年...

  • (?)问号:问号只能出现在日期和星期这两个位置,表示这个位置的值不确定,每天3点执行,所以第六位星期的位置,我们是不需要关注的,就是不确定的值。同时:日期和星期是两个相互排斥的元素,通过问号来表明不指定值。比如,1月10日,比如是星期1,如果在星期的位置是另指定星期二,就前后冲突矛盾了。

  • (-)减号:表达一个范围,如在小时字段中使用“10-12”,则表示从10到12点,即10,11,12

  • (,)逗号:表达一个列表值,如在星期字段中使用“1,2,4”,则表示星期一,星期二,星期四

  • (/)斜杠:如:x/y,x是开始值,y是步长,比如在第一位(秒) 0/15就是,从0秒开始,每15秒,最后就是0,15,30,45,60 另:*/y,等同于0/y

实现定时任务的开启关闭以及定时时间可以配置


​​​​​​​@RestController
@Slf4j
public class ScheduleController {
​
    private final static Map<String,Task> taskMap = new HashMap<String,Task>();
​
    @Autowired
    private ThreadPoolTaskScheduler threadPoolTaskScheduler;
​
    @Bean
    public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
        return new ThreadPoolTaskScheduler();
    }
​
    /**
     * 创建定时任务
     */
    @RequestMapping("/startTask/{id}")
    public String start(@PathVariable("id") String id){
        if(StringUtils.isNotEmpty(id) && !taskMap.containsKey(id)){
            Task task = new Task(id);
            ScheduledFuture<?> future = threadPoolTaskScheduler.schedule(task.getRunnable(),
                new Trigger(){
                    public Date nextExecutionTime(TriggerContext triggerContext){
                        return new CronTrigger(task.getCron())
                                .nextExecutionTime(triggerContext);
                    }
                }
            );
            task.setScheduledFuture(future);
            taskMap.put(task.getTaskId(),task);
        }
        return "success";
    }
​
    /**
     * 更新定时任务的cron
     */
    @RequestMapping("/updateCron/{id}")
    public String update(@RequestBody String cron,@PathVariable("id") String id){
        if(taskMap.containsKey(id)){
            Task task = taskMap.get(id);
            ScheduledFuture<?> future = null;
            try{
                future = threadPoolTaskScheduler.schedule(task.getRunnable(),
                        new Trigger(){
                            public Date nextExecutionTime(TriggerContext triggerContext){
                                return new CronTrigger(cron).nextExecutionTime(triggerContext);
                            }
                        }
                );
            }catch (Exception e){
                return "error";
            }
            task.getScheduledFuture().cancel(true);
            task.setScheduledFuture(future);
        }
        return "success";
    }
​
    /**
     * 删除定时任务
     */
    @RequestMapping("/stopTask/{id}")
    public String stop(@PathVariable("id") String id){
        if(taskMap.containsKey(id)){
            Task task = taskMap.get(id);
            task.getScheduledFuture().cancel(true);
            taskMap.remove(id);
        }
        return "success";
    }
​
    @Slf4j
    @Data
    static class Task{
        private String taskId;
        private Runnable runnable;
        private ScheduledFuture scheduledFuture;
        private String cron;
        public Task(String taskId){
            this.taskId = taskId;
            runnable = ()->{
                log.info("任务taskId:"+taskId);
            };
            cron = "0/5 * * * * ?";
        }
    }
​
}

 

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值