解决定时任务@Scheduled没有准时执行的原因及分析

 更新时间:2023年04月24日 10:31:07   作者:321茄子  
这篇文章主要介绍了解决定时任务@Scheduled没有准时执行的原因及分析,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

定时任务@Scheduled没有准时执行的原因

项目中用到了定时任务往前端推送数据,间隔2秒 @Scheduled(cron = "0/2 * * * * ? "),测试发现,每次任务执行并不是2秒,而是1-5秒之间。

执行时间:::::Wed Nov 30 16:20:19 CST 2022
执行时间:::::Wed Nov 30 16:20:20 CST 2022
执行时间:::::Wed Nov 30 16:20:24 CST 2022
执行时间:::::Wed Nov 30 16:20:29 CST 2022

原因

了解发现,如果程序中没有指定线程池的配置,也就是Spring的Scheduled的默认线程池配置,其线程池的线程数默认为1,也就是说默认情况下,Spring用来处理定时任务的线程只有一个。

如果有定时的处理时间占用时间比较长,那么就会导致下一个定时任务,即使到达了配置的定时时间,也不会立即执行,而是等到前面一个任务处理完成了,才会进行处理。

而项目中还有数个定时任务。

解决法案

是初始一个定时任务执行线程池

@Configuration
public class ScheduleConfig implements SchedulingConfigurer {
 
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        Method[] methods = BatchProperties.Job.class.getMethods();
        int defaultPoolSize = 10;
        int corePoolSize = 0;
        if (methods != null && methods.length > 0) {
            for (Method method : methods) {
                Scheduled annotation = method.getAnnotation(Scheduled.class);
                if (annotation != null) {
                    corePoolSize++;
                }
            }
            if (defaultPoolSize > corePoolSize)
                corePoolSize = defaultPoolSize;
        }
        taskRegistrar.setScheduler(Executors.newScheduledThreadPool(corePoolSize));
 
    }
}

再次测试,跟设置的间隔时间2秒一致。

执行时间:::::Wed Nov 30 16:48:32 CST 2022
执行时间:::::Wed Nov 30 16:48:34 CST 2022
执行时间:::::Wed Nov 30 16:48:36 CST 2022
执行时间:::::Wed Nov 30 16:48:38 CST 2022

定时任务@Scheduled入门

一个最简单的例子

启动类添加注解

@EnableScheduling // 开启定时任务

编写单线程demo

cron 表达式

/**
     * cron 表达式
     * 每2秒执行一次
     * @throws InterruptedException
     */
    @Scheduled(cron = "0/2 * * * * *")
    public void test() throws InterruptedException {
        // 经过测试,使用cron表达式,定时任务第二次会等待第一次执行完毕再开始!
        Thread.sleep(5000L);
        log.info("定时任务测试cron:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
    }

fixedDelay

 /**
     *  fixedDelay:
     *  第一次执行完毕才会执行第二次,时间间隔变为了7秒
     * @throws InterruptedException
     */
    @Scheduled(fixedDelay = 2000L)
    public void test2() throws InterruptedException {
        Thread.sleep(5000L);
        log.info("定时任务测试fixedDelay:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
    }

fixedRate

 /**
     *  fixedRate:
     *  每隔2秒就会执行, 但是因为单线程,所以在5秒后会输出,间隔就是5秒
     * @throws InterruptedException
     */
    @Scheduled(fixedRate = 2000L)
    public void test3() throws InterruptedException {
        Thread.sleep(5000L);
        log.info("定时任务测试fixedRate:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
    }

如果是一起执行这三个定时任务,那么会一个一个的来, 因为只有一个线程.

多线程

/**
 *
 * @author GMaya
 */
@Configuration
@EnableAsync
public class ScheduleConfig {
    @Bean
    public TaskScheduler taskScheduler() {
        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
        taskScheduler.setPoolSize(50); // 设置线程池大小
        return taskScheduler;
    }
}

如果只是加这一个配置类, 确实是使用了多线程, 每个定时任务都互相不影响.

但是一个线程第一次阻塞了,第二次就不行了,所以在定时任务上再加

@Async

就是说你这次失败了, 不要影响我下次的运行

总结

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

相关文章

  • Java实现扑克牌游戏的示例代码

    Java实现扑克牌游戏的示例代码

    想不想带上好朋友来上一局三人扑克呢?这篇文章教你如何利用Java语言实现一个简单的扑克牌游戏,文中的示例代码讲解详细,感兴趣的可以了解一下
    2022-09-09
  • Java线程关闭的3种方法

    Java线程关闭的3种方法

    这篇文章介绍了Java线程关闭的3种方法,有需要的朋友可以参考一下
    2013-10-10
  • idea项目代码打包为jar包的超详细步骤

    idea项目代码打包为jar包的超详细步骤

    因为业务开发场景需要,将开发项目中的Java类打成一个jar包引入到外部工具中,下面这篇文章主要给大家介绍了关于idea项目代码打包为jar包的相关资料,需要的朋友可以参考下
    2023-01-01
  • java建立子类方法总结

    java建立子类方法总结

    在本篇文章里小编给大家分享了关于java建子类的步骤和方法,需要的朋友们跟着学习下。
    2019-05-05
  • JAVA及相关字符集编码问题研究分享

    JAVA及相关字符集编码问题研究分享

    对于JAVA学习,或多或少都会遇到这样的问题:编码基本知识,java,系统软件,url,工具软件等
    2014-10-10
  • Java比较两个对象中全部属性值是否相等的方法

    Java比较两个对象中全部属性值是否相等的方法

    本文主要介绍了Java比较两个对象中全部属性值是否相等的方法,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-08-08
  • 深入浅出RocketMQ的事务消息

    深入浅出RocketMQ的事务消息

    RocketMQ事务消息(Transactional Message)是指应用本地事务和发送消息操作可以被定义到全局事务中,要么同时成功,要么同时失败。本文主要介绍了RocketMQ事务消息的相关知识,需要的可以参考一下
    2023-04-04
  • 如何使用Java调用Linux系统命令

    如何使用Java调用Linux系统命令

    这篇文章主要介绍了如何使用Java调用Linux系统命令,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-11-11
  • SpringBoot中整合knife4j接口文档的实践

    SpringBoot中整合knife4j接口文档的实践

    这篇文章主要介绍了SpringBoot中整合knife4j接口文档的实践,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-09-09
  • java多线程返回值使用示例(callable与futuretask)

    java多线程返回值使用示例(callable与futuretask)

    这篇文章主要介绍了多线程返回值使用示例(callable与futuretask),需要的朋友可以参考下
    2014-04-04

最新评论