@Scheduled注解不能同时执行多个定时任务的解决方案

目录
  • @Scheduled注解不能同时执行多个定时任务
  • @Scheduled同时执行多个定时任务所导致的并发问题
    • @Scheduled的执行顺序
    • @Scheduled同步
    • 控制定时任务的执行顺序

@Scheduled注解不能同时执行多个定时任务

最近在使用定时任务的时候发现,自己写的定时任务没有执行,后来查了上网查了一下,才知道@Scheduled注解的定时任务是单线程的,同一时间段内只能执行一个定时任务,其它定时任务不执行。

需要配置@Scheduled多线程支持,才能实现同一时间段内,执行多个定时任务。

一般情况下面两个定时任务只会执行第一个定时任务,第二个定时任务不会执行。

/**
     * 测试定时任务1 每天22:00:00执行
     */
    @Scheduled(cron = "0 0 22 * * ?")
    public void test() {
 
        for (int i = 0; i < 20; i++) {
            try {
                Thread.sleep(1000 * 10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("=======================测试定时任务执行1=======================");
        }
    }
 
    /**
     * 测试定时任务2 每天22:10:00执行
     */
    @Scheduled(cron = "0 10 22 * * ?")
    public void test2() {
 
        for (int i = 0; i < 20; i++) {
            try {
                Thread.sleep(1000 * 10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("=======================测试定时任务执行2=======================");
        }
    }

要解决上诉问题,就需要配置 @Scheduled多线程支持,添加一个配置类,代码如下:

/**
 * @description: 使@schedule支持多线程的配置类
 * @author: David Allen
 * @create: 2020-12-08
 **/
@Configuration
public class ScheduleConfig implements SchedulingConfigurer {
 
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
 
        Method[] methods = Job.class.getMethods();
        int defaultPoolSize = 3;
        int corePoolSize = 0;
 
        if (!CollectionUtils.isEmpty(Arrays.asList(methods))) {
 
            for (Method method : methods) {
 
                Scheduled annotation = method.getAnnotation(Scheduled.class);
 
                if (annotation != null) {
 
                    corePoolSize++;
                }
            }
            if (defaultPoolSize > corePoolSize) {
 
                corePoolSize = defaultPoolSize;
            }
 
            taskRegistrar.setScheduler(Executors.newScheduledThreadPool(corePoolSize));
        }
    }
}

@Scheduled同时执行多个定时任务所导致的并发问题

@Scheduled的执行顺序

@Scheduled注解会在默认情况下以单线程的方式执行定时任务。

这个“单线程”指两个方面:

  • 如果一个定时任务执行时间大于其任务间隔时间,那么下一次将会等待上一次执行结束后再继续执行。
  • 如果多个定时任务在同一时刻执行,任务会依次执行。

那么这种效果肯定不是我们想要的,为了使@Scheduled效率更高,我们可以通过两种方法将定时任务变成多线程执行:

1、在启动类中配置TaskScheduler线程池大小

@Bean
public TaskScheduler taskScheduler() {
    ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
    taskScheduler.setPoolSize(50);
    return taskScheduler;
}

2、利用Spring提供的@Async注解和@EnableAsync注解

@Component
@EnableAsync
public class TimedTask{
    @Async
    @Scheduled(cron = "0 0/1 * * * ?")//每一分钟执行一次
    public void taskA() {
        //执行你的业务逻辑
    }
    
    @Async
    @Scheduled(cron = "0 0/1 * * * ?")//每一分钟执行一次
    public void taskB() {
        //执行你的业务逻辑
    }

通过以上方式,定时任务将会以多线程的方式开始执行,减小了程序耦合度,提升运行效率。

@Scheduled同步

定时任务在同一时刻开始执行有两种情况:

  • 多个任务的间隔时间相同,如都是1分钟执行一次,那么每一分钟,这些任务都会一起执行。
  • 多个任务的间隔时间不同,但有重合的时刻。如一个任务每天零点执行,另一个任务每一分钟执行,那么这两个任务在零点的时刻会一起执行。

由于任务都是异步的,如果多个任务同时操作同一资源,那么必然会导致错误。

这个时候可以给任务加锁,保证任务互不干扰,拥有在同一时刻执行的线程安全:

@Component
@EnableAsync
public class TimedTask{

    private Object lock = new Object();
    
    @Async
    @Scheduled(cron = "0 0 0 * * ?")//每天零点执行
    public void taskA() {
        synchronized(lock){
               //执行你的业务逻辑
        }
    }
    
    @Async
    @Scheduled(cron = "0 0/1 * * * ?")//每一分钟执行一次
    public void taskB() {
        synchronized(lock){
               //执行你的业务逻辑
        }
    }

控制定时任务的执行顺序

如果对执行顺序有要求的定时任务,有如下两种情况:

1、在某一时刻同时执行

如任务A在零点初始化数据,任务B每分钟更新数据。那么在零点,必须是任务A先执行,其次才是B。但加锁只能保证线程安全,不能保证执行顺序。在这种情况下,我们可以借助redis设置获取锁的顺序,亦或标志字进行执行顺序的判断。

2、总是同时执行

在任务间隔相同的情况下,一般为业务的解耦,不应操作共享资源,应当放至同一个定时任务中执行。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • 详解在Spring3中使用注解(@Scheduled)创建计划任务

    Spring3中加强了注解的使用,其中计划任务也得到了增强,现在创建一个计划任务只需要两步就完成了: 创建一个Java类,添加一个无参无返回值的方法,在方法上用@Scheduled注解修饰一下: 在Spring配置文件中添加三个<task:**** />节点: 最后说明一下,第一步创建的Java类要成为spring可管理的Bean,可以直接写在XML里,也可以@Component一下 示例如下 计划任务类: /** * com.zywang.spring.task.SpringTaskDemo

  • SpringBoot中使用@Scheduled注解创建定时任务的实现

    在项目日常开发过程中,经常需要定时任务来帮我们做一些工作,如清理日志.定时任务的实现方法主要有 Timer.Quartz 以及 elastic-job Timer 实现定时任务 只执行一次的定时任务 Timer timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { System.out.println("2000毫米后执行一次."); } }, 2000); timer.s

  • 我劝你谨慎使用Spring中的@Scheduled注解

    目录 引言 1.@Scheduled失效原因 2.解析流程图 3.使用新的方法 schedule定时任务修改表达式无效 引言 在一些业务场景中需要执行定时操作来完成一些周期性的任务,比如每隔一周删除一周前的某些历史数据以及定时进行某项检测任务等等. 在日常开发中比较简单的实现方式就是使用Spring的@Scheduled(具体使用方法不再赘述)注解. 但是在修改服务器时间时会导致定时任务不执行情况的发生,解决的办法是当修改服务器时间后,将服务进行重启就可以避免此现象的发生. 本文将主要探讨服务器

  • spring @Scheduled注解的使用误区及解决

    目录 @Scheduled注解的使用误区 @Scheduled注解各参数详解 1.cron 2. zone 3. fixedDelay 4. fixedDelayString 5. fixedRate 6. fixedRateString 7. initialDelay 8. initialDelayString @Scheduled注解的使用误区 在使用spring @Scheduled注解时很多人都为cron表达式无法进行配置进行烦恼吧,为何不像quartz般能在applicationCon

  • spring-boot通过@Scheduled配置定时任务及定时任务@Scheduled注解的方法

    串行的定时任务 @Component public class ScheduledTimer { private Logger logger = Logger.getLogger(this.getClass()); /** * 定时任务,1分钟执行1次,更新潜在客户超时客户共享状态 */ @Scheduled(cron="0 0/1 8-20 * * ?") public void executeUpdateCuTask() { Thread current = Thread.curr

  • java使用@Scheduled注解执行定时任务

    前言 在写项目的时候经常需要特定的时间做一些特定的操作,尤其是游戏服务器,维护线程之类的,这时候就需要用到定时器. 如果此时你刚好用的是spring的话,哪么@Scheduled注解是非常好用的. 使用spring @Scheduled注解执行定时任务: 1,在spring-MVC.xml文件中进行配置 2,直接在代码控制层使用即可 package xkhd.game.fix; import org.springframework.beans.factory.annotation.Autowir

  • spring task @Scheduled注解各参数的用法

    目录 参数详解 1. cron 2. zone 3. fixedDelay 4. fixedDelayString 5. fixedRate 6. fixedRateString 7. initialDelay 8. initialDelayString spring @Scheduled注解使用误区 @Scheduled注解的使用这里不详细说明,直接对8个参数进行讲解. 参数详解 1. cron 该参数接收一个cron表达式,cron表达式是一个字符串,字符串以5或6个空格隔开,分开共6或7个

  • @Scheduled注解不能同时执行多个定时任务的解决方案

    目录 @Scheduled注解不能同时执行多个定时任务 @Scheduled同时执行多个定时任务所导致的并发问题 @Scheduled的执行顺序 @Scheduled同步 控制定时任务的执行顺序 @Scheduled注解不能同时执行多个定时任务 最近在使用定时任务的时候发现,自己写的定时任务没有执行,后来查了上网查了一下,才知道@Scheduled注解的定时任务是单线程的,同一时间段内只能执行一个定时任务,其它定时任务不执行. 需要配置@Scheduled多线程支持,才能实现同一时间段内,执行多

  • SpringBoot整合定时任务之实现Scheduled注解的过程(一个注解全解决)

    目录 一.使用场景 二.准备工作 三.开始搭建配置配置启动项 四.结果展示 五.总结 一.使用场景 定时任务在开发中还是比较常见的,比如:定时发送邮件,定时发送信息,定时更新资源,定时更新数据等等... 二.准备工作 在Spring Boot程序中不需要引入其他Maven依赖 (因为spring-boot-starter-web传递依赖了spring-context模块) <dependency> <groupId>org.springframework.boot</grou

  • 关于@Scheduled注解的任务为什么不执行的问题

    目录 概述 举例说明 原因分析 解决方案 概述 在SpringBoot中可以通过@Scheduled来注解定义一个定时任务,但是有时候你可能发现有的定时任务道理时间却没有执行,但是又不是每次都不执行,为什么呢??? 举例说明 下面这段diam定义了一个没隔10s执行一次的定时任务: package com.study.practice.schedule; import lombok.extern.slf4j.Slf4j; import org.springframework.scheduling

  • SpringBoot中定时任务@Scheduled注解的使用解读

    目录 概述 注解定义 参数说明 源码解析 使用详解 定时任务同步/异步执行 fixedRate/fixedDelay区别 项目开发中,经常会遇到定时任务的场景,Spring提供了@Scheduled注解,方便进行定时任务的开发 概述 要使用@Scheduled注解,首先需要在启动类添加@EnableScheduling,启用Spring的计划任务执行功能,这样可以在容器中的任何Spring管理的bean上检测@Scheduled注解,执行计划任务 注解定义 @Target({ElementTyp

随机推荐