项目亮点之定时任务

后台定时任务

后台定时作业是实际项目中经常要用到的,例如每5分钟跑一次新下的订单并发送邮件等等,实际使用非常多。

后台作业类

@Component
public class ScheduledExample {
    // @Scheduled(fixedRate = 5000)
    // 上一次开始执行时间点之后5秒再执行
    public void job1() {
        System.out.println(Thread.currentThread() + " now is " + LocalTime.now());
    }
    // @Scheduled(fixedDelay = 5000)
    // 上一次执行完毕时间点之后5秒再执行
    public void job2() {
        System.out.println(Thread.currentThread() + " now is " + LocalTime.now());
    }
    // @Scheduled(initialDelay = 1000, fixedRate = 5000)
    // 第一次延迟1秒后执行,之后按fixedRate的规则每5秒执行一次
    public void job3() {
        System.out.println( Thread.currentThread() + " now is " +  LocalTime.now());
    }
    //@Scheduled(cron = "0/3 * * * * ?")
    // cron表达式
    public void job4() {
        System.out.println( Thread.currentThread() + " now is " + LocalTime.now());
    }
}

启动类

@SpringBootApplication
@EnableScheduling
@MapperScan("com.bmw.search.dao")
public class SearchApplication {
    public static void main(String[] args) {
        SpringApplication.run(SearchApplication.class, args);
    }
}

cron表达式

Cron表达式是一个字符串,字符串以5或6个空格隔开,分为6或7个域,每一个域代表一个含义,Cron有如下两种语法格式:

1.Seconds Minutes Hours DayofMonth Month DayofWeek Year
2.Seconds Minutes Hours DayofMonth Month DayofWeek

每一个域都使用数字,但还可以出现如下特殊字符,它们的含义是:

*:表示匹配该域的任意值,假如在Minutes域使用*, 即表示每分钟都会触发事件。
?:只能用在DayofMonth和DayofWeek两个域。它也匹配域的任意值,但实际不会。因为DayofMonth和 DayofWeek会相互影响。例如想在每月的20日触发调度,不管20日到底是星期几,则只能使用如下写法: 13 13 15 20 * ?, 其中最后一位只能用?,而不能使用*,如果使用*表示不管星期几都会触发,实际上并不是这样。
L:表示最后,只能出现在DayofWeek和DayofMonth域,如果在DayofWeek域使用5L,意味着在最后的一个星期四触发。

举例:

每隔5秒执行一次:"*/5 * * * * ?"
每隔1分钟执行一次:"0 */1 * * * ?"
每天23点执行一次:"0 0 23 * * ?"
每天凌晨1点执行一次:"0 0 1 * * ?"
每月1号凌晨1点执行一次:"0 0 1 1 * ?"
每天的0点、13点、18点、21点都执行一次:"0 0 0,13,18,21 * * ?"

防止重复启动

@Scheduled定时任务会在上次任务结束时再执行第二次任务,如果第二次任务堵在哪里了,时间会顺延 。

如果担心实际项目启动重复了,比如错误部署了集群,可以采用锁的机制,这样在项目启动的时候在redis中设置锁,执行完毕或者出异常了在finally中把锁进行删除

如果没有锁的机制,代码结构为:
    try {
        //实际的真实任务
    }catch(Exception ex) {
        log.error("",ex);//必须有异常捕获机制,否则的话代码内部抛出了RuntimeException,没有扑获的话任务会异常解除,并且没有错误日志,无法进行跟踪
    }    
如果采用了上面说的用锁来防止重复机制(一般不需要),代码结构如下:
    try {
        //首先是获取锁,如果获取失败,打印log日志,直接返回
        //实际的真正任务
    } catch(Exception ex) {
        //错误日志打印log日志,跟上面的一样,必须有异常捕获机制
    } finally {
        //释放锁,否则的话下次将不能再正常运行
    }
posted @ 2022-07-26 22:21  Faetbwac  阅读(44)  评论(0编辑  收藏  举报