【问题】定时任务整理笔记附问题求大佬解答!!!!

定时任务怎么样避免并发,意思是同一个任务当第一个执行完了,第二才执行,不是一到了间隔时间,不管第一个是否执行完成,第二个就开始执行。

下面小弟整理的笔记

@Scheduled注解是spring boot提供的用于定时任务控制的注解,主要用于控制任务在某个指定时间执行,或者每隔一段时间执行,注意需要配合@EnableScheduling使用,配置@Scheduled主要有三种配置执行时间的方式:cron,fixedRate,fixedDelay

cron

cron是@Scheduled的一个参数,是一个字符串,以空格隔开,允许6或7个域,分别表示秒,分,时,日,月,周,年

表达式就不建议去记怎么玩了,点击去在线生成即可

fixedRate

fixedRate表示自上一次执行时间之后多长时间执行,以ms为单位

fixedDelay

fixedDelay与fixedRate有点类似,不过fixedRate是上一次开始之后计时,fixedDelay是上一次结束之后计时,也就是说,fixedDelay表示上一次执行完毕之后多长时间执行,单位也是ms

initialDelay

initialDelay表示首次延迟多长时间后执行,单位ms,之后按照其他属性指定的规则执行,需要指定别的属性其中一个规则

下面是玩的过程 spring boot项目

正常玩

    @Scheduled(cron = "0/10 * * * * ?")
    public void cs1(){
        System.out.println("第一个定时任务开始 : " + LocalDateTime.now().toLocalTime() +
                "\r\n线程 : " + Thread.currentThread().getName());
        System.out.println();
        try {
            Thread.sleep(60*1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("第一个定时任务结束 : " + LocalDateTime.now().toLocalTime() +
                "\r\n线程 : " + Thread.currentThread().getName());
        System.out.println();

    }

    @Scheduled(cron = "0/10 * * * * ?")
    public void cs2(){
        System.out.println("第二个定时任务开始 : " + LocalDateTime.now().toLocalTime() +
                "\r\n线程 : " + Thread.currentThread().getName());
        System.out.println();

        System.out.println("第二个定时任务结束 : " + LocalDateTime.now().toLocalTime() +
                "\r\n线程 : " + Thread.currentThread().getName());
        System.out.println();
    }

输出结果
在这里插入图片描述

可以看出是单线程环境,但是不满足我要求,然后看到说可以加个注解实现异步

其中一个方法加上@Async启用异步

    @Async
    @Scheduled(cron = "0/10 * * * * ?")
    public void cs1(){
        System.out.println("第一个定时任务开始 : " + LocalDateTime.now().toLocalTime() +
                "\r\n线程 : " + Thread.currentThread().getName());
        System.out.println();
        try {
            Thread.sleep(60*1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("第一个定时任务结束 : " + LocalDateTime.now().toLocalTime() +
                "\r\n线程 : " + Thread.currentThread().getName());
        System.out.println();

    }

    @Scheduled(cron = "0/10 * * * * ?")
    public void cs2(){
        System.out.println("第二个定时任务开始 : " + LocalDateTime.now().toLocalTime() +
                "\r\n线程 : " + Thread.currentThread().getName());
        System.out.println();

        System.out.println("第二个定时任务结束 : " + LocalDateTime.now().toLocalTime() +
                "\r\n线程 : " + Thread.currentThread().getName());
        System.out.println();
    }

输出结果

在这里插入图片描述

但是这样不行,可能我上个任务数据太多都没执行完成,这也就会导致数据重复消费了,不科学,继续找

网上找了一下,好多地方都推荐这两个属性fixedDelay 和 fixedRate,分别干啥上面写了

fixedRate走一波

    @Async
    @Scheduled(fixedRate = 1000*10)
    public void cs1(){
        System.out.println("第一个定时任务开始 : " + LocalDateTime.now().toLocalTime() +
                "\r\n线程 : " + Thread.currentThread().getName());
        System.out.println();
        try {
            Thread.sleep(60*1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("第一个定时任务结束 : " + LocalDateTime.now().toLocalTime() +
                "\r\n线程 : " + Thread.currentThread().getName());
        System.out.println();

    }

    @Scheduled(cron = "0/10 * * * * ?")
    public void cs2(){
        System.out.println("第二个定时任务开始 : " + LocalDateTime.now().toLocalTime() +
                "\r\n线程 : " + Thread.currentThread().getName());
        System.out.println();

        System.out.println("第二个定时任务结束 : " + LocalDateTime.now().toLocalTime() +
                "\r\n线程 : " + Thread.currentThread().getName());
        System.out.println();
    }

输出结果

假装有图,结果同上,不管执行不,到点就执行

fixedDelay走一波

是否可以就看这个了,毕竟fixedDelay这个属性表示上一次执行完毕之后多长时间执行,看字面意思,结束了,才会执行下一次,心心念念的走一波

    @Async
    @Scheduled(fixedDelay = 1000*10)
    public void cs1(){
        System.out.println("第一个定时任务开始 : " + LocalDateTime.now().toLocalTime() +
                "\r\n线程 : " + Thread.currentThread().getName());
        System.out.println();
        try {
            Thread.sleep(60*1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("第一个定时任务结束 : " + LocalDateTime.now().toLocalTime() +
                "\r\n线程 : " + Thread.currentThread().getName());
        System.out.println();

    }

    @Scheduled(cron = "0/10 * * * * ?")
    public void cs2(){
        System.out.println("第二个定时任务开始 : " + LocalDateTime.now().toLocalTime() +
                "\r\n线程 : " + Thread.currentThread().getName());
        System.out.println();

        System.out.println("第二个定时任务结束 : " + LocalDateTime.now().toLocalTime() +
                "\r\n线程 : " + Thread.currentThread().getName());
        System.out.println();
    }

见证奇迹的输出结果

假装有结果吧,我都不想看

结论

  • spring 是单线程的,不管多少个任务都是一个线程再跑
  • 某个方法使用注解 @Async,开启异步执行,那个其他定时任务依然遵循上个结论,使用了@Async这个注解的会多个线程执行,不管选择 cron,fixedRate,fixedDelay这三里的谁都一样

问题

  • 只有一个任务单独执行,其他任务依然共用一个线程
  • 单独执行的这个任务,需要操作数据库,所以只能一个时间只能有一个线程在执行
  • 这个定时任务,每分钟执行一次,大多数时候没有数据操作
  • 有数据的时候,一般执行三到五分钟

所以问题来了,每分钟执行一次,有数据的时候,此任务没有执行完成,单线程的时候,会被其他定时任务阻塞,针对这个定时任务,开启异步处理,那此任务就会在没有执行完成的时候,下个一分钟间隔到来前又执行一次

咋整!!咋整!!咋整!!!!!

上面已解决

代码

    @Async
    @Scheduled(cron = "0/10 * * * * ?")
    public void cs1(){
        if (i == 1){
            i++;
            System.out.println("第一个定时任务开始 : " + LocalDateTime.now().toLocalTime() +
                    "\r\n线程 : " + Thread.currentThread().getName());
            System.out.println();
            try {
                Thread.sleep(60*1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("第一个定时任务结束 : " + LocalDateTime.now().toLocalTime() +
                    "\r\n线程 : " + Thread.currentThread().getName());
            System.out.println();
            i--;
        }else {
            System.out.println("定时任务未执行" + LocalDateTime.now().toLocalTime() +
                    "\r\n线程 : " + Thread.currentThread().getName());
        }
    }

//    @Async
    @Scheduled(cron = "0/10 * * * * ?")
    public void cs2(){
        System.out.println("第二个定时任务开始 : " + LocalDateTime.now().toLocalTime() +
                "\r\n线程 : " + Thread.currentThread().getName());
        System.out.println();

        System.out.println("第二个定时任务结束 : " + LocalDateTime.now().toLocalTime() +
                "\r\n线程 : " + Thread.currentThread().getName());
        System.out.println();
    }

输出结果在这里插入图片描述

现在有个小问题

到时间之后定时任务是另外一个线程在执行,但是我没有弄线程池,代码里面也并没有Thread.sleep(60*1000)这种线程相关的代码,那么到时候新开的线程是怎么样的,对线程理解有点弱,如果按照这种写法会不会有问题,有问题是什么样的问题

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值