@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、总是同时执行

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

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

@Scheduled注解不能同时执行多个定时任务的解决方案的更多相关文章

  1. 一种angular的方法级的缓存注解(装饰器)

    本篇文章主要介绍了一种angular的方法级的缓存注解(装饰器),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  2. Spring详细讲解@Autowired注解

    @Autowired注解可以用在类属性,构造函数,setter方法和函数参数上,该注解可以准确地控制bean在何处如何自动装配的过程。在默认情况下,该注解是类型驱动的注入

  3. 详解springboot测试类注解

    这篇文章主要介绍了springboot测试类注解,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  4. Selenium执行JavaScript脚本的方法示例

    这篇文章主要介绍了Selenium执行JavaScript脚本的方法示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  5. SpringBoot中使用@scheduled定时执行任务的坑

    本文主要介绍了SpringBoot中使用@scheduled定时执行任务的坑,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  6. @FeignClient注解中属性contextId的使用说明

    这篇文章主要介绍了@FeignClient注解中属性contextId的使用说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  7. php Yii2框架创建定时任务方法详解

    Yii2是一个基于组件、用于开发大型Web应用的高性能PHP框架,采用严格的OOP编写,并有着完善的库引用以及全面的教程,该框架提供了Web 2.0应用开发所需要的几乎一切功能,是最有效率的PHP框架之一

  8. @Schedule 如何解决定时任务推迟执行

    这篇文章主要介绍了@Schedule 如何解决定时任务推迟执行问题。具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  9. Java泛型与注解全面分析讲解

    Java 泛型(generics)是 Jdk 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。Annotation(注解)是JDK1.5及以后版本引入的。它可以用于创建文档,跟踪代码中的依赖性,甚至执行基本编译时检查。需要的可以参考一下

  10. Nodejs中读取中文文件编码问题、发送邮件和定时任务实例

    这篇文章主要介绍了Nodejs中读取中文文件编码问题、发送邮件和定时任务实例,本文使用了3个模块来解决这3个需求,并给出了代码操作实例,需要的朋友可以参考下

随机推荐

  1. 基于EJB技术的商务预订系统的开发

    用EJB结构开发的应用程序是可伸缩的、事务型的、多用户安全的。总的来说,EJB是一个组件事务监控的标准服务器端的组件模型。基于EJB技术的系统结构模型EJB结构是一个服务端组件结构,是一个层次性结构,其结构模型如图1所示。图2:商务预订系统的构架EntityBean是为了现实世界的对象建造的模型,这些对象通常是数据库的一些持久记录。

  2. Java利用POI实现导入导出Excel表格

    这篇文章主要为大家详细介绍了Java利用POI实现导入导出Excel表格,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  3. Mybatis分页插件PageHelper手写实现示例

    这篇文章主要为大家介绍了Mybatis分页插件PageHelper手写实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  4. (jsp/html)网页上嵌入播放器(常用播放器代码整理)

    网页上嵌入播放器,只要在HTML上添加以上代码就OK了,下面整理了一些常用的播放器代码,总有一款适合你,感兴趣的朋友可以参考下哈,希望对你有所帮助

  5. Java 阻塞队列BlockingQueue详解

    本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景,通过实例代码介绍了Java 阻塞队列BlockingQueue的相关知识,需要的朋友可以参考下

  6. Java异常Exception详细讲解

    异常就是不正常,比如当我们身体出现了异常我们会根据身体情况选择喝开水、吃药、看病、等 异常处理方法。 java异常处理机制是我们java语言使用异常处理机制为程序提供了错误处理的能力,程序出现的错误,程序可以安全的退出,以保证程序正常的运行等

  7. Java Bean 作用域及它的几种类型介绍

    这篇文章主要介绍了Java Bean作用域及它的几种类型介绍,Spring框架作为一个管理Bean的IoC容器,那么Bean自然是Spring中的重要资源了,那Bean的作用域又是什么,接下来我们一起进入文章详细学习吧

  8. 面试突击之跨域问题的解决方案详解

    跨域问题本质是浏览器的一种保护机制,它的初衷是为了保证用户的安全,防止恶意网站窃取数据。那怎么解决这个问题呢?接下来我们一起来看

  9. Mybatis-Plus接口BaseMapper与Services使用详解

    这篇文章主要为大家介绍了Mybatis-Plus接口BaseMapper与Services使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  10. mybatis-plus雪花算法增强idworker的实现

    今天聊聊在mybatis-plus中引入分布式ID生成框架idworker,进一步增强实现生成分布式唯一ID,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

返回
顶部