spring @Scheduled 并发

Posted jtlgb

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring @Scheduled 并发相关的知识,希望对你有一定的参考价值。

一.spring定时任务配置

applicationContext.xml:红色代码部分为需要配置的部分。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
   xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx"
   xmlns:context="http://www.springframework.org/schema/context"
   xmlns:task="http://www.springframework.org/schema/task"
   xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
   <!--   定时器配置   -->
   <task:annotation-driven/>
   <task:scheduler id="myScheduler" pool-size="5"/>

  

注意事项:<task:scheduler id="myScheduler" pool-size="5"/>这段配置为非必须,配置这段的原因是spring定时任务默认是单线程的。配置了这段表示不同定时任务不论是否在同一时间点执行,任务之间互不影响(即多线程执行)。但是自己还是会影响自己。下面介绍具体问题以及解决方式。

二.测试1(不加<task:scheduler id="myScheduler" pool-size="5"/>)
方法代码:

public class QuartzServiceImpl implements QuartzService {


    //1.简易定时器-(每10秒执行一次,执行时间为20秒)
    @Scheduled(cron = "0/10 * *  * * ? ")
    public void taskA() {
        try {
            System.out.println(DateUtils.forMatDate(new Date())+"||A任务每10秒执行一次..");
            Thread.sleep(20*1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    //2.简易定时器-每5秒执行一次
    @Scheduled(cron="0/5 * *  * * ? ")
    public void taskB(){
        System.err.println(DateUtils.forMatDate(new Date())+"||B任务每5秒执行一次进入测试");
    }

}

  

结果:很明显A任务和B任务会相互影响。B任务正常应该是从15秒到20秒,但是20秒的时候执行了A任务(A任务又执行了20秒),因此B任务在40秒的时候再次执行。

技术图片

二.测试2(加<task:scheduler id="myScheduler" pool-size="5"/>)
方法代码:同上,这次加上了<task:scheduler id="myScheduler" pool-size="5"/>这段配置

结果:上面的配置将spirng定时任务变为多线程,因此任务之间不会相互影响了。很明显A任务不再影响B任务的执行。正常的按每隔5秒钟执行一次。但是A任务是10秒钟执行一次,按理说应该41分30秒的时候执行了一次,下一次执行应该是40秒,而这里却变为了40分00秒的执行才执行。并没有按照每隔10秒钟执行一次。这也是上面我提到的加了线程池之后自己任务的执行时间会影响自己的下次执行。

 

三.测试3(加@Async注解)
方法代码:两个方法上面分别加了 @Async注解-即异步执行

public class QuartzServiceImpl implements QuartzService {


    //1.简易定时器-(每10秒执行一次,执行时间为20秒)
    @Scheduled(cron = "0/10 * *  * * ? ")
    @Async
    public void taskA() {
        try {
            System.out.println(DateUtils.forMatDate(new Date())+"||A任务每10秒执行一次..");
            Thread.sleep(20*1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    //2.简易定时器-每5秒执行一次
    @Scheduled(cron="0/5 * *  * * ? ")
    @Async
    public void taskB(){
        System.err.println(DateUtils.forMatDate(new Date())+"||B任务每5秒执行一次进入测试");
    }

  

结果:结果A任务和B任务都不会影响,并且自己也不会因为自己的执行时间过长而影响自己。

A任务每10秒正常执行一次。B任务每5秒正常执行一次。

 

 

四.总结
1.简单使用定时任务测试一即可。

2.解决并发使用测试二或测试三即可(建议使用测试二)。

原因,如果你的代码真的出现了测试三的情况,即本任务的执行时间影响了本任务的下次执行,那么你应该优化你的代码,sql语句等。而不是,让程序一直"欠费"的执行下去。

以上是关于spring @Scheduled 并发的主要内容,如果未能解决你的问题,请参考以下文章

Spring @Scheduled @Async联合实现调度任务

springboot @scheduled 并发

springboot + @scheduled 多任务并发

Spring boot实现定时任务二:使用注解@scheduled和@EnableScheduling

Spring @Scheduled 使用详解

spring的@scheduled定时怎么加返回值