美文网首页
定时任务的线程池默认为1

定时任务的线程池默认为1

作者: flyjar | 来源:发表于2021-07-06 08:40 被阅读0次

    背景

    在真实的Java开发环境中,我们经常会需要用到定时任务来帮助我们完成一些特殊的任务,比如我最近写的晚上11点定时拉取第三方的数据入库,晚上12点清理脏数据等等。

    如果我们使用SpringBoot来开发,那么定时任务将会变得非常简单。SpringBoot默认已经帮我们封装好了相关定时任务的组件和配置,我们只需要在相应的地方加上@Schedule注解就可以实现定时任务。

    启动定时任务

    SpringBoot项目只需要在启动类上加上@EnableScheduling即可开启定时任务

    @SpringBootApplication
    @EnableScheduling
    public class ScheduleTestApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(ScheduleTestApplication.class, args);
        }
    
    }
    

    创建定时任务

    SpringBoot的Scheduler支持四种定时任务格式

    • fixedRate:固定速率执行,例如每3秒执行一次
    • fixedDelay:固定延迟执行,例如距离上一次调用成功后3秒执行
    • initialDelay:初始延迟任务,例如任务开启过3秒后再执行,之后以固定频率或者间隔执行
    • cron:使用 Cron 表达式执行定时任务

    以上在企业开发中经常用到的是cron表达式,可以说掌握了cron表达式,基本就掌握了SpringBoot的定时任务了。

    使用cron表达式

    @Component
    public class ScheduleTask {
    
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    
        //每隔5秒执行一次该方法
        @Scheduled(cron = "*/5 * * * * ?")
        public void testScheduleTask() {
            System.out.println("SpringBoot的定时任务" + Thread.currentThread().getName() + sdf.format(new Date()));
        }
    
    }
    
    image

    @Schedule默认线程池大小

    其实@Schedule默认线程池大小为1,我们可以实验得出这个结论。

    @Component
    public class ScheduleTask {
    
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    
        //固定2秒执行一次该方法
        @Scheduled(fixedRate = 2000)
        public void testScheduleTask() {
            try{
                Thread.sleep(6000);
                System.out.println("SpringBoot的定时任务" + Thread.currentThread().getName() + sdf.format(new Date()));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
    }
    
    image

    结果每隔6秒执行一次,可以看到线程的名字为scheduleing-12021-01-12,表示都是用的同一个线程,默认@Schedule是开启一个线程。

    一般情况下使用默认@Schedule没有问题,但是如果有多个定时任务,每个定时任务执行时间可能不短的情况下,会有可能出现定时任务一直没有机会执行的情况。

    第一种解决方案:异步执行定时任务

    给该方法加上@Async进行异步处理,看看会是什么效果~

    @Component
    @EnableAsync
    public class ScheduleTask {
    
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    
        @Async
        @Scheduled(fixedRate = 2000)
        public void testScheduleTask() {
            try{
                Thread.sleep(6000);
                System.out.println("SpringBoot的定时任务" + Thread.currentThread().getName() + sdf.format(new Date()));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
    }
    
    image

    可以看出线程的名字都是不一样的,然后每隔2秒的执行一次该方法,异步处理不受方法内的时间影响,并行执行。

    第二种解决方案:调整定时任务的线程池数量

    Spring Boot 版本2.1.0之后,可以直接在配置文件中设置 spring.task.scheduling.pool.size 的值来配置计划任务线程池的容量,而不需要额外再写一个类。

    spring.task.scheduling.pool.size=5
    

    相关文章

      网友评论

          本文标题:定时任务的线程池默认为1

          本文链接:https://www.haomeiwen.com/subject/xpwwultx.html