定时任务时间过长会不会影响下次的执行?- 第331篇

图片

关历史文章(阅读本文前,您可能需要先看下之前的系列👇

国内最全的Spring Boot系列之三

2020上半年发文汇总「值得收藏」

立方阶时间复杂度怎么算-征战沙场- 第326篇

SpringBoot的controller为什么不能并行执行?同一个浏览器连续多次访问同一个url竟然是串行的?- 第329篇

悟纤:定时任务如果执行的时间很长的话,那么下一次还能按时执行嘛?

师傅:To be or notto be,that is a question.

悟纤:师傅?

图片

师傅:你这个问题吗?为师也不是一两句话就能够和你说明白的。

悟纤:那就用三句话说明一下。

图片

师傅:你这杠精又要来了,打住。

图片

悟纤:师傅,师傅,你赶紧和徒儿讲讲吗。

师傅:那今天为师就和你好好聊聊。

图片

 

前言

       有关定时任务会不会延迟执行了,可以看文章《为什么你要阻碍我,你看我扎不扎你「见鬼,定时任务延迟执行?」 - 第292篇》

https://mp.weixin.qq.com/s/G1-92E7jvvy5Ngp7nIIykg

       本质上来讲,我们这一篇文章的问题的答案在上一篇已经算是给出了答案了,只是没有那么明确,这一节我们来明确的说一下。

       针对这个问题「定时任务时间过长会不会影响下次的执行」,也是考虑定时任务是单线程的还是多线程的。

一、单线程

       有这么一个定时任务:

@Scheduled(cron="10 * *  * * ? ")
  public void aTask(){
    DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    System.out.println(Thread.currentThread().getName()+":" +sdf.format(new Date())+" --> A任务每10秒执行一次");
    try {
      TimeUnit.SECONDS.sleep(70);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }

如果按照我们的想像的情况下,现在8:00:00的话,那么8:00:10的时候执行第一次,8:01:10的时候执行第二次,以此类推,但是在单线程的情况下却不是这样子执行的,当让我们的定时任务执行过长超过了下一次要执行的时候,那么就需要等到下一次才能执行了,我们看下执行的情况:

scheduling-1:2020-09-28 20:02:10--> A任务每10秒执行一次

scheduling-1:2020-09-28 20:04:10--> A任务每10秒执行一次

scheduling-1:2020-09-28 20:06:10--> A任务每10秒执行一次

       中间总是会隔了1分钟。

 

二、多线程

       如何开启多线程还不懂嘛,那么请阅读《为什么你要阻碍我,你看我扎不扎你「见鬼,定时任务延迟执行?」 - 第292篇》。

       在多线程情况下,结果是什么样子呢?我们还是直接看下控制塔的打印在来给出结果吧:

myThread-1:2020-09-28 20:09:10--> A任务每10秒执行一次

myThread-1:2020-09-28 20:11:10--> A任务每10秒执行一次

       从这里我们可以看出多线程情况下还是有影响的。

 

三、异步任务

如何在定时任务中使用异步任务还不懂嘛,那么请阅读《为什么你要阻碍我,你看我扎不扎你「见鬼,定时任务延迟执行?」 - 第292篇》。

       在异步任务的情况下,我们看下结果:

task-1:2020-09-28 20:13:10 -->A任务每10秒执行一次

task-2:2020-09-28 20:14:10 -->A任务每10秒执行一次

       从这里我们可以看出在异步任务的情况下,就不会延迟了,从上面的打印我们可以看出是不同的任务在执行下一次的定时任务。即使上一个任务还没执行完成也不影响下一次的执行了。

 

四、多线程定时任务执行时间过长的思考

       这里我们主要是针对开启了多线程的情况下,单线程为啥不考虑呐。

我们在文章《为什么你要阻碍我,你看我扎不扎你「见鬼,定时任务延迟执行?」 - 第292篇》中说明,如果有两个任务A和B,如果A执行过长的话是会影响B的执行的。

那么在实际项目中,我们肯定不希望A的执行影响到B的执行了。所以正常情况下都会开启多线程的支持的。

在接下来的讨论都是基于多线程开启的情况下的定时任务的思考。

4.1 同一个定时任务执行时间过长会影响下一次的执行吗?

       这个我们在前面分析了,答案是会有影响的,那么如何解决这个问题呐?

       有两种思路:①使用异步任务,使用@Async即可。②使用线程,将耗时的代码放到线程的run方法中进行执行。

①使用异步任务,使用@Async即可

@Scheduled(cron="10 * *  * * ? ")
  @Async //使用异步任务,使用@Async即可
  public void aTask(){
    DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    System.out.println(Thread.currentThread().getName()+":" +sdf.format(new Date())+" --> A任务每10秒执行一次");
    try {
      TimeUnit.SECONDS.sleep(70);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }

②使用线程,将耗时的代码放到线程的run方法中进行执行。

@Scheduled(cron="10 * *  * * ? ")
  public void aTask(){
    new Thread() {
      public void run() {
        DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println(Thread.currentThread().getName()+":" +sdf.format(new Date())+" --> A任务每10秒执行一次");
        try {
          TimeUnit.SECONDS.sleep(70);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      };
    }.start();
  }

4.2 不同定时任务会互相影响吗?

       这个是不会影响的,我们在之前的文章中已经说明过了,这里不重复进行说明了。

4.3 重复执行问题如何解决?

       如果我们解决了定时任务执行过长影响下一次执行的问题,也就是能够根据设置的表达式进行定时执行了,那么又会可能产生什么新的问题呢?就是定时任务重复执行的问题

       一般我们的定时任务都会查库然后进行操作的,如果此时上一个定时任务未执行完成,下次的定时任务又开始了,那么很有可能会获取到重复的数据。那么定时任务就会被重复执行了。

       这里提供两种思路进行解决吧:

(1)锁表行记录:如果这表就是一个定时任务的表的话,那么可以将表行记录进行锁住。如果不是定时任务的表,是其它业务表的话,锁表行记录就不可行了。

(2)缓存id:我们一般获取到的数据都是有id的,那么我们可以将当前正在处理的id缓存起来,如果下个任务进来了,发现此id已经在缓存中,说明这个id已经正在定时任务中进行处理了,直接舍此id,进行下个id即可。。

 

4.4不同的任务类中的定时任务方法也会互相影响吗(单线程下)

会相互影响的,Spring单线程的话,会管理所有的定时任务的,和是否是不是一个类定义的定时任务没有关系。

测试结果如下(MyTask1和MyTask2):

scheduling-1:2020-07-02 15:04:25--> B任务每5秒执行一次

scheduling-1:2020-07-02 15:04:30--> A任务每10秒执行一次

scheduling-1:2020-07-02 15:04:50--> B任务每5秒执行一次

scheduling-1:2020-07-02 15:04:55--> B任务每5秒执行一次

我们会发现在默认配置单线程的情况下,B任务收到影响了,一旦A任务执行的话,B任务就会延迟执行了。

 

悟纤小结

       我们把《为什么你要阻碍我,你看我扎不扎你「见鬼,定时任务延迟执行?」 - 第292篇》和本节的知识做个汇总。

师傅:徒儿,你表现的时候到了。

悟纤:师傅,我来也。

图片

(1)单线程情况下A任务的延迟会影响到B任务的执行。

(2)引起定时任务延迟原因:Spring/Spring Boot的定时任务默认是单线程 (敲重点)。

(3)解决定时任务延迟问题:异步任务和多线程(敲重点)。

(4)异步任务定时任务执行情况:A/B任务互相不影响,A的定时任务执行过长不会影响A的下次执行。

(5)多线程定时任务执行情况:A/B任务互相不影响,A的定时任务执行过长会影响到A的下次执行。

(6)定时任务重复执行的方案:①锁表行记录(不能锁业务表行记录,因为可能会影响正常的业务执行);②缓存ID(可以是任务ID,也可以是业务表ID)

我就是我,是颜色不一样的烟火。
我就是我,是与众不同的小苹果。

à悟空学院:https://t.cn/Rg3fKJD

学院中有Spring Boot相关的课程!点击「阅读原文」进行查看!

SpringBoot视频:http://t.cn/A6ZagYTi

SpringBoot交流平台:https://t.cn/R3QDhU0

SpringSecurity5.0视频:http://t.cn/A6ZadMBe

ShardingJDBC分库分表:http://t.cn/A6ZarrqS

分布式事务解决方案:http://t.cn/A6ZaBnIr

JVM内存模型调优实战:http://t.cn/A6wWMVqG

Spring入门到精通:https://t.cn/A6bFcDh4

大话设计模式之爱你:https://dwz.cn/wqO0MAy7

悟纤 CSDN认证博客专家 知远公司创始人 架构师 访问1000万+
「公众号SpringBoot」:
①阿里巴巴前高级研发工程师;
②估值20亿美金的Blued架构师;
③北京知远公司创始人;
④浙江甄才公司架构师;
⑤云课堂学员10000+;
⑥博客访问量1000万+;
⑦10年互联网行业从业;
⑧360万的访问《从零开始学SprngBoot》作者;
⑨技术加盟多个独立项目。
已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 酷酷鲨 设计师:CSDN官方博客 返回首页
实付 19.90元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值