SpringBoot通过@Scheduled注解启动定时任务

内容分享2周前发布
0 0 0

SpringBoot可以通过@Scheduled注解启用定时任务。

1.简单使用

第一要在SpringBoot启动类上面开启Schedule,即加上@EnableScheduling注解,且@Scheduled注解需要在被spring管理的bean中才生效,即需要使用@Component注解。
@Scheduled修饰的方法将会根据配置定时调用该方法。例如cron或者固定间隔。

    @Scheduled(cron = "0/3 * * * * ?")
//    @Scheduled(fixedDelay = 3 * 1000)
//    @Scheduled(fixedRate = 3 * 1000)
    private void test(){
        System.out.println("test");
    }

2.不同配置的差别

配置方式 配置含义 任务执行时间过久的差别
cron 根据配置的cron表达式进行调用 任务执行中,再次到了触发时间,不执行,等任务执行完了之后的下一次触发,再执行
fixedDelay 方法执行结束之后,在进行计时,单位毫秒 不存在同时触发
fixedRate 方法执行结束开始时进行计时,单位毫秒 阻塞等待,上次执行完立马再次执行,不过貌似不会阻塞过多任务

@Component
public class ScheduledTest {

    @Resource
    private ScheduledTaskHolder scheduledTaskHolder;

    @Scheduled(cron = "0/3 * * * * ?")
//    @Scheduled(fixedDelay = 3 * 1000)
//    @Scheduled(fixedRate = 3 * 1000)
    private void test() throws InterruptedException{
        System.out.println("Start=>" + LocalDateTime.now());
        // 获取任务数 方式存疑
        System.out.println(scheduledTaskHolder.getScheduledTasks().size());
        Thread.sleep(5000);
        System.out.println("end=>" + LocalDateTime.now());
    }
}

不论哪种方式 任务数貌似都是1,不过获取任务数的方式不保证正确。

3. 开启多线程

默认只有一个线程去执行任务,如果有多个被@Scheduled修饰的方法,同时只有一个在运行。
如果有多个任务一般都不会想让他们去抢同一个线程去执行,那么就需要开启多线程模式。

3.1 @EnableAsync + @Async

网上最简单粗暴的方式是给类加上@EnableAsync并且给方法加上@Async

@Component
@EnableAsync
public class ScheduledTest {

    @Scheduled(cron = "0/3 * * * * ?")
    @Async
    protected void test() throws InterruptedException{
        System.out.println("Start=>" + LocalDateTime.now());
        Thread.sleep(5000);
        System.out.println("end=>" + LocalDateTime.now());
    }
}

细心的小伙伴应该发现test方法从private变成protected了,由于@Async是通过动态代理的方式来将该任务提交到线程池中去执行的。而且这个线程池貌似没有限制核心线程数(我没看具体实现)。而Spring的动态代理通过操控字节码来生成子类,以继承的方式实现的,所以test方法不能是private的。

这个方法并没有改变@Schduled本身的线程池,不同的定时任务依旧是在一个线程中执行的,只不过变成了在这个线程中提交到另一个线程池,达到了不阻塞的结果。所以上面分析的任务执行时间过长的分析也就失效了,由于对@Scheduled本身来说,任务瞬间就执行结束了。

也就是说,你的同一个任务可能同时有多个在执行,且如果不是所有的@Scheduled方法都被@Async修饰,那么那个没被修饰的方法,依旧会阻塞别的被@Async修饰的方法的提交。

3.2 代码配置

@Configuration
public class ScheduledConfig implements SchedulingConfigurer {

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.setScheduler(Executors.newScheduledThreadPool(10));
    }
}

3.3配置文件

spring:
  task:
    scheduling:
      pool:
        size: 10

我觉得用后面两个就好了,@Async毕竟不是专门给@Scheduled用的,虽然简单粗暴。而后两种方式线程数要看情况设置,具体的自己看着来吧~

© 版权声明

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
none
暂无评论...