返回顶部
首页 > 资讯 > 后端开发 > Python >@Scheduled注解不能同时执行多个定时任务的解决方案
  • 607
分享到

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

2024-04-02 19:04:59 607人浏览 八月长安

Python 官方文档:入门教程 => 点击学习

摘要

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

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

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

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

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


    @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=======================");
        }
    }
 
    
    @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多线程支持,添加一个配置类,代码如下:


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

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

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

--结束END--

本文标题: @Scheduled注解不能同时执行多个定时任务的解决方案

本文链接: https://lsjlt.com/news/168812.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作