0
点赞
收藏
分享

微信扫一扫

springboot中的定时任务

在实际项目中,经常需要执行周期性任务,比如每天凌晨备份数据、每小时同步第三方数据、定时清理临时文件等。如果手动触发这些任务,不仅效率低还容易出错。Spring Boot 提供的@Scheduled注解,就像一个精准的 “自动闹钟”,能按预设时间自动执行任务,无需人工干预,让周期性操作变得简单高效。

一、开启定时任务支持:激活自动执行能力

要使用@Scheduled,首先得在 Spring Boot 应用中开启定时任务功能,只需在启动类上添加@EnableScheduling注解,这一步相当于给系统装上了 “定时任务调度器”,让应用具备识别和执行定时任务的能力。

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
@EnableScheduling // 开启定时任务支持
public class ScheduledDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(ScheduledDemoApplication.class, args);
    }
}

二、基础用法:三种常见定时策略

@Scheduled支持多种定时方式,可根据业务需求选择合适的配置,就像闹钟能设置每天重复、每隔一段时间响铃一样灵活。

1. 固定延迟执行(fixedDelay)

任务执行完成后,间隔固定时间再执行下一次任务,适合需要等上一次任务结束后再启动的场景,比如连续备份数据,避免两次备份冲突。

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class FixedDelayTask {

    // 上一次任务执行完成后,间隔5秒执行下一次
    @Scheduled(fixedDelay = 5000) // 时间单位:毫秒
    public void backupData() {
        System.out.println("开始执行数据备份任务,当前时间:" + new java.util.Date());
        // 模拟备份耗时操作
        try {
            Thread.sleep(2000); // 模拟2秒备份时间
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("数据备份任务执行完成,当前时间:" + new java.util.Date());
    }
}

控制台输出会呈现 “执行完成→间隔 5 秒→再次执行” 的规律,比如:

开始执行数据备份任务,当前时间:Wed Oct 22 10:00:00 CST 2025
数据备份任务执行完成,当前时间:Wed Oct 22 10:00:02 CST 2025
开始执行数据备份任务,当前时间:Wed Oct 22 10:00:07 CST 2025(间隔5秒)

2. 固定速率执行(fixedRate)

每隔固定时间就启动一次任务,不管上一次任务是否完成,适合任务执行时间短、无需等待上一次结束的场景,比如定时检查设备状态。

@Component
public class FixedRateTask {

    // 每隔3秒启动一次任务
    @Scheduled(fixedRate = 3000)
    public void checkDeviceStatus() {
        System.out.println("开始检查设备状态,当前时间:" + new java.util.Date());
        // 模拟检查耗时
        try {
            Thread.sleep(1000); // 模拟1秒检查时间
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("设备状态检查完成,当前时间:" + new java.util.Date());
    }
}

控制台输出会呈现 “每隔 3 秒启动” 的规律,即使上一次任务已完成,也会按固定速率启动下一次:

开始检查设备状态,当前时间:Wed Oct 22 10:00:00 CST 2025
设备状态检查完成,当前时间:Wed Oct 22 10:00:01 CST 2025
开始检查设备状态,当前时间:Wed Oct 22 10:00:03 CST 2025(间隔3秒)

3. Cron 表达式执行(cron)

通过 Cron 表达式设置复杂的定时规则,比如 “每天凌晨 2 点执行”“每周一上午 10 点 30 分执行”,适合需要精准定时的场景,灵活性最高。

@Component
public class CronTask {

    // 每天凌晨2点执行任务(Cron表达式:秒 分 时 日 月 周 年,年可省略)
    @Scheduled(cron = "0 0 2 * * ?")
    public void cleanTempFiles() {
        System.out.println("开始清理临时文件,当前时间:" + new java.util.Date());
        // 模拟清理耗时
        try {
            Thread.sleep(3000); // 模拟3秒清理时间
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("临时文件清理完成,当前时间:" + new java.util.Date());
    }

    // 每小时的第15分钟执行任务(比如10:15、11:15)
    @Scheduled(cron = "0 15 * * * ?")
    public void syncThirdPartyData() {
        System.out.println("开始同步第三方数据,当前时间:" + new java.util.Date());
        // 模拟同步耗时
        try {
            Thread.sleep(5000); // 模拟5秒同步时间
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("第三方数据同步完成,当前时间:" + new java.util.Date());
    }
}

常见 Cron 表达式参考:

  • 0 0 2 * * ?:每天凌晨 2 点

  • 0 30 10 ? * MON:每周一上午 10 点 30 分

  • 0 0/10 * * * ?:每 10 分钟(0 分、10 分、20 分...)

三、高级用法:自定义定时任务线程池

Spring Boot 默认使用单线程执行所有定时任务,若多个任务同时触发,会出现任务排队等待的情况。实际开发中,建议自定义定时任务线程池,让多个任务可并行执行,提升效率。

1. 配置自定义线程池

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;

@Configuration
public class ScheduledConfig {

    @Bean
    public ThreadPoolTaskScheduler taskScheduler() {
        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
        scheduler.setPoolSize(5); // 线程池大小,可同时执行5个定时任务
        scheduler.setThreadNamePrefix("ScheduledTask-"); // 线程名称前缀
        scheduler.setAwaitTerminationSeconds(60); // 关闭时等待任务完成的时间
        scheduler.setWaitForTasksToCompleteOnShutdown(true); // 关闭时是否等待任务完成
        return scheduler;
    }
}

2. 测试并行执行效果

定义两个定时任务,让它们在同一时间触发,观察线程池是否并行处理:

@Component
public class ParallelScheduledTasks {

    // 每隔2秒执行(固定速率)
    @Scheduled(fixedRate = 2000)
    public void taskOne() {
        System.out.println("任务一执行,线程:" + Thread.currentThread().getName() + ",时间:" + new java.util.Date());
        try {
            Thread.sleep(1500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    // 每隔2秒执行(固定速率)
    @Scheduled(fixedRate = 2000)
    public void taskTwo() {
        System.out.println("任务二执行,线程:" + Thread.currentThread().getName() + ",时间:" + new java.util.Date());
        try {
            Thread.sleep(1500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

控制台输出会显示两个任务在不同线程中并行执行,不会相互阻塞:

任务一执行,线程:ScheduledTask-1,时间:Wed Oct 22 10:00:00 CST 2025
任务二执行,线程:ScheduledTask-2,时间:Wed Oct 22 10:00:00 CST 2025
任务一执行,线程:ScheduledTask-1,时间:Wed Oct 22 10:00:02 CST 2025
任务二执行,线程:ScheduledTask-2,时间:Wed Oct 22 10:00:02 CST 2025

四、注意事项

  1. @Scheduled注解的方法需定义在@Component或@Service等 Spring 管理的 Bean 中,否则无法被识别。

  2. 定时任务方法不能有返回值,若有返回值会导致任务执行异常,建议定义为void类型。

  3. 若任务执行时间超过定时周期(如 fixedRate=3 秒,任务执行耗时 5 秒),fixedRate 会出现任务堆积,此时建议改用 fixedDelay 或调整线程池大小。

  4. 生产环境中,对于关键定时任务,建议添加日志记录和失败重试机制(如结合@Retryable注解),避免任务执行失败后无迹可寻。

  5. Cron 表达式中 “周” 和 “日” 不能同时指定具体值(如同时指定 “1”(周一一)和 “5”(5 号)),否则会导致定时规则冲突,建议用 “?” 忽略其中一个。

@Scheduled注解让 Spring Boot 应用轻松实现定时任务,从简单的固定间隔执行到复杂的 Cron 表达式定时,再到自定义线程池提升并行能力,满足不同场景下的定时需求。合理运用@Scheduled,能大幅减少人工操作,让系统自动化运行更可靠、更高效。

举报

相关推荐

0 条评论