前言
定时任务允许我们自动化处理、数据备份、资源清理等操作,提高系统的稳定性和可靠性。
- 定时备份数据库
- 每天发送项目切面数据邮件
- 定时刷新页面缓存
- 延时关单失败的数据兜底处理
快速开始
下面将介绍 Java 中三种常见的定时任务实现方式。
Java Timer
java.util.Timer
适用于简单的定时任务需求。由于 Timer 是单线程会造成任务阻塞,并且单个任务执行异常会造成整个定时任务终止执行。
java
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println("hello world");
}
}, 0, 1000);
说明下后两个参数分别是delay延迟执行,和period执行间隔,单位都是毫秒。
ScheduledThreadPoolExecutor
java
ScheduledExecutorService service = Executors.newScheduledThreadPool(64);
service.scheduleAtFixedRate(() -> System.out.println("hello world"), 0, 1, TimeUnit.SECONDS);
相比于 Timer
,ScheduledThreadPoolExecutor
基于线程池可以更好地控制并发性,并且任务之间也互不影响。
Spring @Scheduled
通过 @Scheduled 注解,你可以在 Spring 容器中非常简单地配置定时任务。既能定时任务代码与业务逻辑更加紧密集成,又能享受 Spring 提供的便捷特性。
注:需要手动打开 @EnableScheduling 标识。
java
@Slf4j
@Component
public class MyScheduledTasks {
@Scheduled(fixedDelay = 5000) // 间隔5秒执行一次
public void task1() {
log.info("任务 task1 执行...");
// 执行任务逻辑
}
@Scheduled(fixedRate = 10000) // 每隔10秒执行一次
public void task2() {
log.info("任务 task2 执行...");
// 执行任务逻辑
}
}
- fixedDelay:上一次任务执行完成后到下一次任务开始执行的时间间隔。
- fixedRate:上一次任务开始执行后到下一次任务开始执行的时间间隔。
第三方组件
传统的 Quartz,当下流行的 xxl-job 等等。技术选型时,需要结合当前业务的具体情况。
常见问题
分布式多次执行
- 增加任务执行分布式锁,保证单节点执行;
- 使用数据库全局任务执行状态,只有一个节点能修改该标记位;
- 引入分布式调度中心,例如 xxl-job;
根据项目具体需求、技术栈和复杂度来选择最合适的方法。
执行时间超过间隔时间
- 任务异步执行,实际执行时间不影响后续任务调度;
- 采用固定延迟策略,例如 fixedDelay 直至上个任务执行完成;