Java 定时任务 - 从基础到高阶使用 - 从 Timer 到 Quart
在 Java 开发中,定时任务是常见需求,比如定时发送邮件、清理日志、同步数据等。从简单的 Timer 到企业级的 Quartz Scheduler。
基础:使用 Timer 和 TimerTask
Timer 和 TimerTask 是 Java 提供的内置工具,适合简单场景。Timer 负责调度,TimerTask 定义任务逻辑。
示例代码
import java.util.Timer;
import java.util.TimerTask;public class TimerExample {public static void main(String[] args) {Timer timer = new Timer();TimerTask task = new TimerTask() {@Overridepublic void run() {System.out.println("任务执行时间: " + System.currentTimeMillis());}};// 延迟 1 秒后执行,每 2 秒重复执行timer.schedule(task, 1000, 2000);// 10 秒后停止new Timer().schedule(new TimerTask() {@Overridepublic void run() {timer.cancel();System.out.println("Timer 停止");}}, 10000);}
}
代码解释
• 创建 Timer 和 TimerTask:
Timer 是调度器,负责管理任务的执行时间。
TimerTask 是一个抽象类,通过重写 run() 方法定义任务逻辑。
• 调度任务:
schedule(task, delay, period):延迟 delay 毫秒后执行任务,每隔 period 毫秒重复执行。
• 停止 Timer:
使用 timer.cancel() 停止调度器。
优缺点
• 优点:简单易用,无需额外依赖。
• 缺点:单线程执行,任务阻塞会影响后续任务;异常可能导致整个 Timer 终止。
适用场景
轻量级任务,如简单的状态检查或日志清理。
中级:使用 ScheduledExecutorService
ScheduledExecutorService 是 Java 并发包(java.util.concurrent)中的工具,基于线程池,支持多任务并发执行,比 Timer 更现代、更稳定。
示例代码
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;public class ScheduledExecutorExample {public static void main(String[] args) {ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);Runnable task = () -> System.out.println("任务执行时间: " + System.currentTimeMillis());// 延迟 1 秒后执行,每 2 秒重复(固定频率)scheduler.scheduleAtFixedRate(task, 1, 2, TimeUnit.SECONDS);// 10 秒后停止scheduler.schedule(() -> {scheduler.shutdown();System.out.println("Scheduler 停止");}, 10, TimeUnit.SECONDS);}
}
代码解释
• 创建调度器:
Executors.newScheduledThreadPool(2) 创建一个容量为 2 的线程池,支持并发执行。
• 调度任务:
scheduleAtFixedRate(task, initialDelay, period, unit):延迟 initialDelay 后执行任务,每隔 period 时间单位重复执行。
• 停止调度器:
使用 scheduler.shutdown() 优雅关闭线程池。
• 固定频率 vs 固定延迟:
scheduleAtFixedRate:固定时间间隔执行,不考虑任务耗时。
scheduleWithFixedDelay:任务执行完后,等待固定延迟再执行下一次。
优缺点
• 优点:支持多线程并发,异常不会影响调度器,调度方式灵活。
• 缺点:不支持 cron 表达式,需手动管理线程池。
适用场景
需要并发执行多个定时任务,如批量数据处理、状态监控。
高阶:使用 Spring 的 @Scheduled
在 Spring 项目中,@Scheduled 注解是实现定时任务的首选,简单易用,支持 cron 表达式,适合复杂调度需求。
示例代码
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;@Configuration
@EnableScheduling
@Component
public class SpringScheduledExample {// 每 5 秒执行一次@Scheduled(fixedRate = 5000)public void fixedRateTask() {System.out.println("固定频率任务: " + System.currentTimeMillis());}// 每 5 秒延迟执行(任务完成后等待 5 秒)@Scheduled(fixedDelay = 5000)public void fixedDelayTask() {System.out.println("固定延迟任务: " + System.currentTimeMillis());}// 使用 cron 表达式,每分钟执行一次@Scheduled(cron = "0 * * * * ?")public void cronTask() {System.out.println("Cron 任务: " + System.currentTimeMillis());}
}
代码解释
• 启用调度:
@EnableScheduling 注解启用 Spring 的定时任务支持。
• 定义任务:
@Scheduled(fixedRate = 5000):每 5 秒执行一次任务。
@Scheduled(fixedDelay = 5000):任务完成后,等待 5 秒再执行下一次。
@Scheduled(cron = “0 * * * * ?”):使用 cron 表达式,每分钟的第 0 秒执行。
• Cron 表达式:
格式:秒 分 时 天 月 星期。
配置线程池(可选)
Spring 默认使用单线程调度器,任务阻塞可能导致延迟。可以通过自定义线程池优化:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;@Configuration
public class SchedulerConfig {@Beanpublic ThreadPoolTaskScheduler taskScheduler() {ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();scheduler.setPoolSize(10); // 设置线程池大小scheduler.setThreadNamePrefix("scheduled-task-");return scheduler;}
}
代码解释
• ThreadPoolTaskScheduler:Spring 提供的线程池调度器。
• setPoolSize(10):设置线程池大小为 10,支持并发执行。
• setThreadNamePrefix:设置线程名前缀,便于日志追踪。
优缺点
• 优点:注解驱动,配置简单;支持 cron 表达式;与 Spring 生态无缝集成。
• 缺点:依赖 Spring 框架,分布式场景需额外扩展。
适用场景
Spring 项目的定时任务,如缓存刷新、数据同步。
进阶:使用 Quartz Scheduler
Quartz 是一个功能强大的开源调度框架,适合企业级复杂场景,支持分布式调度、任务持久化和动态管理。
示例代码(Spring 集成 Quartz)
1. 添加依赖(pom.xml)
<dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz</artifactId><version>2.3.2</version>
</dependency>
<dependency><groupId>org.springframework</groupId><artifactId>spring-context-support</artifactId><version>5.3.22</version>
</dependency>
2. 定义 Job
import org.quartz.Job;
import org.quartz.JobExecutionContext;public class MyQuartzJob implements Job {@Overridepublic void execute(JobExecutionContext context) {System.out.println("Quartz Job 执行: " + System.currentTimeMillis());}
}
3. 配置 Quartz
import org.quartz.JobDetail;
import org.quartz.Trigger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.JobDetailFactoryBean;
import org.springframework.scheduling.quartz.CronTriggerFactoryBean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;@Configuration
public class QuartzConfig {@Beanpublic JobDetailFactoryBean jobDetail() {JobDetailFactoryBean factory = new JobDetailFactoryBean();factory.setJobClass(MyQuartzJob.class);factory.setDurability(true);return factory;}@Beanpublic CronTriggerFactoryBean trigger(JobDetail jobDetail) {CronTriggerFactoryBean factory = new CronTriggerFactoryBean();factory.setJobDetail(jobDetail);factory.setCronExpression("0/5 * * * * ?"); // 每 5 秒执行return factory;}@Beanpublic SchedulerFactoryBean scheduler(Trigger trigger, JobDetail jobDetail) {SchedulerFactoryBean factory = new SchedulerFactoryBean();factory.setTriggers(trigger);factory.setJobDetails(jobDetail);return factory;}
}
代码解释
• Job 定义:
MyQuartzJob 实现 Job 接口,重写 execute 方法定义任务逻辑。
• JobDetail 配置:
JobDetailFactoryBean 用于创建 JobDetail,绑定具体的 Job 类。
setDurability(true):即使没有触发器,Job 也会保留。
• Trigger 配置:
CronTriggerFactoryBean 定义触发器,使用 cron 表达式 0/5 * * * * ?(每 5 秒触发)。
• Scheduler 配置:
SchedulerFactoryBean 整合 Job 和 Trigger,启动调度。
优缺点
• 优点:支持复杂调度、任务持久化、分布式调度;动态管理任务。
• 缺点:配置复杂,学习成本较高。
适用场景
• 企业级应用,如订单处理、报表生成。
• 分布式系统或需要动态调整任务的场景。
结语
选择建议:
• 简单任务:用 Timer 或 ScheduledExecutorService,轻量快速。
• Spring 项目:首选 @Scheduled,简单高效。
• 企业级复杂调度:选择 Quartz 或分布式框架(如 XXL-Job)。
注意事项
• 异常处理:在任务中捕获异常,避免调度器崩溃;记录日志便于排查问题。
• 资源管理:确保线程池或调度器及时关闭,释放资源。
• 性能优化:根据任务量调整线程池大小;对于大数据量任务,考虑分片或异步执行。