SpringTask定时任务怎么用?@Scheduled注解参数详解

 更新时间:2026年07月27日 08:45:55   作者:小璐乱撞xllz  
还在为Spring定时任务犯愁?本文手把手教你使用@Scheduled注解,详解Cron表达式语法、fixedRate与fixedDelay的区别,以及如何配置多线程解决任务阻塞问题,轻松搞定数据备份、报表生成等场景

基本概念

Spring Task 主要是用来实现定时任务的,定时任务的业务场景非常常见,比如:

① 数据定时备份

② 视频网站定时发布视频

③ 系统定时生成数据报表

我们可以直接使用 Spring 提供的 @Scheduled 注解即可定义定时任务,默认情况下,@Scheduled 的任务都在 Spring 创建的大小为 1 的默认线程池中执行(ScheduledThreadPoolExecutor)。

该注解常用的几个参数如下:

1.cron

使用 Cron 表达式定义任务的执行时间。Cron 表达式是一种用于调度任务的字符串,通常用于定义定时任务的执行时间。

它由六或七个字段组成,每个字段代表一个时间单位,依次为秒、分钟、小时、日期、月份、星期几和(可选的)年份。各字段通过空格分隔

在线 Cron 表达式生成器:http://cron.qqe2.com/

每一个字段的有效范围如下:

秒(Seconds):0-59

分钟(Minutes):0-59

小时(Hours):0-23

日期(Day of Month):1-31

月份(Month):1-12 或 JAN-DEC

星期几(Day of Week):0-7(0、7 表示星期天,1 表示星期二,以此类推)或 SUN-SAT

年份(Year,可选):1970-2099

特殊字符:

*:代表所有可能的值。例如,在秒字段为 * 表示每一秒触发

,:用于指定多个值。例如,在分钟字段中 5,10 表示第 5 和第 10 分钟

-:用于指定一个范围的值。例如,在小时字段中 1-5 表示从 1 点到 5 点每小时触发一次

/:表示起始时间开始触发,然后每隔固定时间触发一次。例如,在秒字段中 0/15 表示起始时间 0s 触发一次,之后每隔 15 秒触发一次

?:只能在日期(Day of Month)和星期几(Day of Week)字段中使用,表示不指定值,在需要指定某一个字段而不关心另一个字段时使用。例如,想要在每月的 20 日触发而不管 20 日是星期几,则在 Day of Week 字段中使用 ?

L:只能在日期(Day of Month)和星期几(Day of Week)字段中使用,表示最后。例如,在 Day of Week 字段使用 5L 表示在最后一个星期四触发

W:只能在日期(Day of Month)字段中使用,表示工作日,系统将在离指定日期的最近的有效工作日触发事件。例如,在 Day of Month 中使用 5W,如果 5 日是星期六,则在 4 日(星期五)触发。如果 5 日是星期天,则在 6 日(周一)触发;如果 5 日是星期一到星期五中的一天,就在 5 日触发。另外,W 的最近寻找不会跨过月份

#:只能在日期(Day of Month)字段中使用,用于指定每月的第几个星期几。例如,2#1 表示某月的第一个星期一

示例:

(1)每天凌晨 1 点执行一次

0 0 1 * * *

(2)每隔5分钟执行一次

0 */5 * * * *

(3)每天下午 2 点到下午 2:05 期间,每 1 分钟执行一次

0 0-5 14 * * *

(4)每周一的早上 7 点执行一次

0 0 7 ? * MON

2.fixedRate

按固定的频率执行任务,从任务开始执行的时间算起,每隔固定的时间间隔重新执行一次,不管前一个任务是否完成

但这里需要注意的是,如果使用默认的方式,不修改线程池参数,即单线程执行,如果前一个任务执行时长大于定时时长,下一个任务的执行会等到上一个任务执行完后立即执行。但是如果增大线程池的线程数量,如果线程数量足够,下一个任务的执行不会被上一个任务所阻塞,而是会在定时结束后就立即执行,即出现任务并行执行的情况

举例:

(1)任务执行时间为 3s,间隔时间为 5s

  • 第一次执行:0s 开始
  • 第二次执行:5s 开始
  • 第三次执行:10s 开始

(2)任务执行时间为 6s,间隔时间为 5s(单线程)

  • 第一次执行:0s 开始
  • 第二次执行:6s 开始
  • 第三次执行:12s 开始

3.fixedDelay

在前一个任务完成后,等待固定的时间间隔再开始执行下一个任务

举例:

任务执行时间为 3s,间隔时间为 5s

  • 第一次执行:0s 开始
  • 第二次执行:3s(任务完成) + 5s(延迟时间) = 8s 开始
  • 第三次执行: 11s(任务完成) + 5s(延迟时间) = 16s 开始

4.initialDelay

在应用启动后,初始延迟一定时间后开始任务,一般会配合 fixedRatefixedDelay 使用,来指定延迟的时间

代码实现

1.在 Springboot 启动类加上 @EnableScheduling 注解,表示启用 Spring 框架中的计划任务调度功能

@SpringBootApplication
@EnableScheduling
public class TimedTaskDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(TimedTaskDemoApplication.class, args);
    }

}

2.编写任务类,在定时任务方法上面加上 @Scheduled 注解,注意在类的上面要加上 @Component 注解。这里 根据四种常用的参数分别编写不同的任务

(1)cron

@Component
public class ScheduleTask {
    
    @Scheduled(cron = "*/1 * * * * *") // 每秒执行一次
    public void task1() {
        System.out.println(LocalDateTime.now() + "定时任务");
    }
    
}

测试结果:

(2)fixedRate

@Component
public class ScheduleTask {
    
    private int times = 1;
    
    @Scheduled(fixedRate = 5000) // 延迟 5s
    public void task2() {
        System.out.println(LocalDateTime.now() + "定时任务开始,当前次数:" + times);
        try {
            Thread.sleep(3000); // 执行 3s
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(LocalDateTime.now() + "定时任务结束,当前次数;" + times);
        times++;
    }
    
}

测试结果:

这里的延迟时间大于任务的执行时间,但当任务的执行时间大于了延迟时间,结果又会不相同,测试代码如下:

@Component
public class ScheduleTask {
    
    private int times = 1;
    
    @Scheduled(fixedRate = 5000) // 延时 5s
    public void task3() {
        System.out.println(LocalDateTime.now() + "定时任务开始,当前次数:" + times);
        try {
            Thread.sleep(7000); // 执行 7s
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(LocalDateTime.now() + "定时任务结束,当前次数;" + times);
        times++;
    }
    
}

可以看到,设定的延时时间为 5s,而实际上延迟的时间是 7s,原因在于默认线程池大小为 1,任务只能串行执行,后面的任务会受到前面任务执行耗时的影响

这里可以选择开启多线程,在类上方加上 @EnableAsync 注解,对应的方法上方加上 @Async 注解即可

@EnableAsync
@Component
public class ScheduleTask {
    
    @Async
    @Scheduled(fixedRate = 5000) // 延迟 5s
    public void tasks4() {
        System.out.println(LocalDateTime.now() + "定时任务开始,当前线程:" + Thread.currentThread());
        try {
            Thread.sleep(7000); // 执行 7s
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
    
}

测试结果:

可以看到此时的延时时间就是 5s

(3)fixedDelay

@Component
public class ScheduleTask {
    
    private int times = 1;
    
    @Scheduled(fixedDelay = 5000) // 延时 5s
    public void task5() {
        System.out.println(LocalDateTime.now() + "定时任务开始,当前次数:" + times);
        try {
            Thread.sleep(3000); // 执行 3s
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(LocalDateTime.now() + "定时任务结束,当前次数;" + times);
        times++;
    }
    
}

测试结果:

可以看到,下一次任务的开始时间是上一次任务的结束时间 + 延时时间

(4)initialDelay

@Component
public class ScheduleTask {
    
    private int times = 1;
    
    // 初始 1s,延时 5s
    @Scheduled(initialDelay = 1000, fixedRate = 5000)
    public void task6() {
        System.out.println(LocalDateTime.now() + "定时任务开始,当前次数:" + times);
        try {
            Thread.sleep(3000); // 执行 7s
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(LocalDateTime.now() + "定时任务结束,当前次数;" + times);
        times++;
    }
    
}

测试结果:

可以看到,是在应用启动后 1s 开始第一次任务,随后每次延时了 5s

总结

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

相关文章

  • Java的Comparable,Comparator和Cloneable三大接口详解

    Java的Comparable,Comparator和Cloneable三大接口详解

    这篇文章主要为大家详细介绍了Java的Comparable,Comparator和Cloneable的接口,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-03-03
  • Springboot开发之利用Docker和Kubernetes部署微服务

    Springboot开发之利用Docker和Kubernetes部署微服务

    这篇文章主要介绍了如何将Spring Boot开发的微服务通过Docker容器化,并使用Kubernetes进行部署和管理,帮助读者掌握现代云原生应用的完整开发部署流程,有需要的可以了解下
    2025-03-03
  • Java中将接口返回的字节串转为文件详解

    Java中将接口返回的字节串转为文件详解

    这篇文章主要给大家介绍了关于Java中将接口返回的字节串转为文件的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2021-11-11
  • java多线程之线程安全的单例模式

    java多线程之线程安全的单例模式

    这篇文章主要为大家详细介绍了java多线程之线程安全的单例模式,文章内容全面,感兴趣的小伙伴们可以参考一下
    2016-03-03
  • java之使用stream对日期排序方式

    java之使用stream对日期排序方式

    这篇文章主要介绍了java之使用stream对日期排序方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-04-04
  • Java集合之整体结构

    Java集合之整体结构

    Java中集合类是Java编程中使用最频繁、最方便的类。接下来通过本文给大家介绍Java集合之整体结构,一起看看吧
    2016-05-05
  • 详解JavaEE使用过滤器实现登录(用户自动登录 安全登录 取消自动登录黑用户禁止登录)

    详解JavaEE使用过滤器实现登录(用户自动登录 安全登录 取消自动登录黑用户禁止登录)

    主要介绍用户的自动登录和取消自动登录,以及实现一天自动登录或者n天实现自动登录,当用户ip被加入到黑名单之后,直接利用过滤器返回一个警告页面。接下来通过本文给大家介绍JavaEE使用过滤器实现登录的相关知识,感兴趣的朋友一起学习吧
    2016-05-05
  • Spring security用户URL权限FilterSecurityInterceptor使用解析

    Spring security用户URL权限FilterSecurityInterceptor使用解析

    这篇文章主要介绍了Spring security用户URL权限FilterSecurityInterceptor使用解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-12-12
  • Java读取properties配置文件的实现过程

    Java读取properties配置文件的实现过程

    这篇文章主要介绍了Java读取properties配置文件的实现过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2026-03-03
  • java中的 toString()方法实例代码

    java中的 toString()方法实例代码

    toString()方法 相信大家都用到过,一般用于以字符串的形式返回对象的相关数据。这篇文章主要介绍了java中的 toString()方法,需要的朋友可以参考下
    2017-05-05

最新评论