Java中通过@Scheduled注解实现周期执行,需启用@EnableScheduling、方法在Spring Bean中且非static/private/无参、配置fixedDelay/fixedRate/cron触发规则。

Java 中通过定时方法(Scheduled Method)实现周期执行,最常用的是 Spring 框架自带的 @Scheduled 注解,它依赖 Spring 的任务调度模块,底层基于 TaskScheduler(默认使用 ThreadPoolTaskScheduler)。要让方法被周期执行,需满足三个基本条件:启用调度支持、方法满足可见性与签名要求、配置合法的触发规则。
启用 @Scheduled 支持
在 Spring Boot 或 Spring 应用的主配置类(如启动类)上添加 @EnableScheduling 注解:
@SpringBootApplication
@EnableScheduling
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
该注解会自动注册 ScheduledAnnotationBeanPostProcessor,扫描并处理所有带 @Scheduled 的 Bean 方法。
立即学习“Java免费学习笔记(深入)”;
编写可调度的方法
被 @Scheduled 标记的方法必须满足:
- 定义在由 Spring 容器管理的 Bean 中(即类上有
@Component、@Service等注解) - 方法不能是
static或private,推荐为public或protected - 方法不能有参数(Spring 5.3+ 允许带
java.time.Clock参数,但一般不建议) - 返回值类型应为
void(若需异步或结果处理,可结合@Async)
示例:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
@Service
public class DataSyncService {
@Scheduled(fixedDelay = 30000) // 每30秒执行一次,以上次执行结束为起点
public void syncUserData() {
System.out.println("同步用户数据: " + LocalDateTime.now());
}
@Scheduled(cron = "0 0 * * * ?") // 每小时整点触发(秒 分 时 日 月 周)
public void cleanExpiredCache() {
// 清理逻辑
}
}
配置触发策略(fixedDelay / fixedRate / cron)
三种主流方式适用不同场景:
- fixedDelay:上次执行完成后,等待指定毫秒数再执行下一次。适合执行耗时不固定、需避免重叠的任务(如 HTTP 调用、文件处理)
- fixedRate:按固定频率执行,不管上次是否完成。可能并发执行(除非加锁),适合轻量、幂等操作(如心跳上报)
- cron:支持 Unix cron 表达式,精度到秒(Spring 扩展为6位:秒 分 时 日 月 周),适合复杂时间规则(如“每月1号凌晨2点”、“每周五18:00”)
注意:cron 表达式中周字段默认以周日为 0(0-6),也可用英文缩写(SUN-SAT);若需兼容周一为 1,可在配置中设 spring.task.scheduling.cron.weekday-starts-with-monday=true(Spring Boot 3.2+)。
进阶:动态修改调度参数 & 异常处理
@Scheduled 本身不支持运行时修改,如需动态控制,可改用 TaskScheduler 编程式调度:
- 注入
TaskScheduler,调用scheduler.scheduleAtFixedRate()或scheduleWithFixedDelay() - 保存
ScheduledFuture引用,后续可cancel(true)停止 - 在方法内捕获异常并记录,避免单次失败导致整个调度中断(
@Scheduled方法抛出未捕获异常会终止后续执行)
例如:
@Autowired
private TaskScheduler taskScheduler;
private ScheduledFuture> syncTask;
public void startSync(long intervalMs) {
if (syncTask != null && !syncTask.isCancelled()) syncTask.cancel(true);
syncTask = taskScheduler.scheduleAtFixedRate(
() -> {
try { syncUserData(); }
catch (Exception e) { log.error("同步失败", e); }
},
Duration.ofMillis(intervalMs)
);
}

















