Java的各类定时任务实现
在 Java 中实现定时任务有多种方式,下面详细介绍各种方法的使用:
1. 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() {
@Override
public void run() {
System.out.println("定时任务执行了,时间: " + new Date());
}
};
// 安排任务执行
// 延迟1秒后执行,然后每5秒执行一次
timer.schedule(task, 1000, 5000);
// 在特定时间执行
// Calendar calendar = Calendar.getInstance();
// calendar.add(Calendar.SECOND, 10);
// timer.schedule(task, calendar.getTime());
// 10秒后停止定时器
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
timer.cancel();
}
}
2. ScheduledExecutorService(推荐)
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
public class ScheduledExecutorExample {
public static void main(String[] args) {
// 创建调度线程池
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
// 任务1:固定延迟执行
Runnable task1 = () -> {
System.out.println("任务1执行 - " + Thread.currentThread().getName() + " - " + new Date());
};
// 任务2:带返回值的任务
ScheduledFuture<String> task2 = scheduler.schedule(() -> {
System.out.println("一次性任务执行");
return "任务完成";
}, 3, TimeUnit.SECONDS);
// 安排任务执行
// 延迟2秒后开始执行,然后每5秒执行一次(固定延迟)
ScheduledFuture<?> scheduledTask = scheduler.scheduleWithFixedDelay(task1, 2, 5, TimeUnit.SECONDS);
// 固定频率执行(不考虑任务执行时间)
// scheduler.scheduleAtFixedRate(task1, 2, 5, TimeUnit.SECONDS);
try {
// 运行20秒
Thread.sleep(20000);
// 取消任务
scheduledTask.cancel(false);
// 获取一次性任务的结果
if (task2.isDone()) {
System.out.println("一次性任务结果: " + task2.get());
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭调度器
scheduler.shutdown();
try {
if (!scheduler.awaitTermination(5, TimeUnit.SECONDS)) {
scheduler.shutdownNow();
}
} catch (InterruptedException e) {
scheduler.shutdownNow();
}
}
}
}
3. Spring Framework 的 @Scheduled(最常用)
配置类或者主启动类上添加 @EnableScheduling注解
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
@Configuration
@EnableScheduling
public class SpringSchedulerConfig {
// 启用定时任务支持
}
定时任务类添加@Component
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit;
@Component
public class SpringScheduledTasks {
/**
* 固定速率执行 - 每5秒执行一次
* 从上一次开始时间计算
*/
@Scheduled(fixedRate = 5000)
public void fixedRateTask() {
System.out.println("固定速率任务 - " + LocalDateTime.now());
}
/**
* 固定延迟执行 - 上一次执行完成后延迟3秒再执行
*/
@Scheduled(fixedDelay = 3000)
public void fixedDelayTask() {
try {
// 模拟任务执行时间
TimeUnit.SECONDS.sleep(1);
System.out.println("固定延迟任务 - " + LocalDateTime.now());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
/**
* 初始延迟 - 应用启动后延迟10秒开始执行,然后每30秒执行一次
*/
@Scheduled(initialDelay = 10000, fixedRate = 30000)
public void initialDelayTask() {
System.out.println("初始延迟任务 - " + LocalDateTime.now());
}
/**
* Cron 表达式 - 更灵活的时间控制
*/
@Scheduled(cron = "0 */2 * * * ?") // 每2分钟执行一次
public void cronTask() {
System.out.println("Cron任务执行 - " + LocalDateTime.now());
}
/**
* Cron 表达式示例
*/
@Scheduled(cron = "0 0 12 * * ?") // 每天中午12点执行
public void noonTask() {
System.out.println("中午任务执行 - " + LocalDateTime.now());
}
/**
* 支持占位符,从配置文件中读取
*/
@Scheduled(cron = "${task.cron.expression:0 */5 * * * ?}")
public void configurableTask() {
System.out.println("可配置任务 - " + LocalDateTime.now());
}
}
4. Quartz Scheduler(企业级)
添加依赖(Maven)
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.2</version>
</dependency>
Quartz 配置
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
public class QuartzExample {
// 定义任务
public static class SimpleJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
System.out.println("Quartz任务执行 - " + new Date());
// 获取传递的参数
JobDataMap dataMap = context.getJobDetail().getJobDataMap();
String message = dataMap.getString("message");
if (message != null) {
System.out.println("消息: " + message);
}
}
}
public static void main(String[] args) throws SchedulerException {
// 创建调度器
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
// 定义任务详情
JobDetail job = JobBuilder.newJob(SimpleJob.class)
.withIdentity("simpleJob", "group1")
.usingJobData("message", "Hello Quartz!")
.build();
// 定义触发器
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("simpleTrigger", "group1")
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(10)
.repeatForever())
.build();
// 安排任务
scheduler.scheduleJob(job, trigger);
// 启动调度器
scheduler.start();
// 运行一段时间后关闭
try {
Thread.sleep(60000);
} catch (InterruptedException e) {
e.printStackTrace();
}
scheduler.shutdown();
}
}
5. 基于 Spring + Quartz 的集成
配置类
import org.quartz.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class QuartzConfig {
@Bean
public JobDetail sampleJobDetail() {
return JobBuilder.newJob(SampleQuartzJob.class)
.withIdentity("sampleJob")
.storeDurably()
.build();
}
@Bean
public Trigger sampleJobTrigger() {
SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(30)
.repeatForever();
return TriggerBuilder.newTrigger()
.forJob(sampleJobDetail())
.withIdentity("sampleTrigger")
.withSchedule(scheduleBuilder)
.build();
}
}
任务类
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;
public class SampleQuartzJob extends QuartzJobBean {
@Override
protected void executeInternal(JobExecutionContext context)
throws JobExecutionException {
System.out.println("Spring Quartz 任务执行 - " + new Date());
}
}
6. Cron 表达式详解
/**
* Cron 表达式格式: [秒] [分] [时] [日] [月] [周] [年] (年可选)
*
* 常用示例:
* "0 0 12 * * ?" 每天12点
* "0 15 10 ? * *" 每天10:15
* "0 0/5 14,18 * * ?" 每天14点和18点,每5分钟一次
* "0 0-5 14 * * ?" 每天14:00到14:05每分钟执行
* "0 0/30 9-17 * * ?" 朝九晚五工作时间内每半小时
* "0 0 12 ? * WED" 每周三中午12点
* "0 15 10 15 * ?" 每月15日上午10:15
*/
7. 最佳实践和注意事项
异常处理
@Component
public class SafeScheduledTask {
@Scheduled(fixedRate = 5000)
public void safeTask() {
try {
// 业务逻辑
performBusinessLogic();
} catch (Exception e) {
// 记录日志,但不抛出异常,避免任务停止
System.err.println("定时任务执行失败: " + e.getMessage());
// 可以添加告警逻辑
}
}
private void performBusinessLogic() {
// 模拟业务逻辑
if (Math.random() < 0.1) {
throw new RuntimeException("模拟异常");
}
System.out.println("业务逻辑执行成功");
}
}
分布式环境考虑
@Component
public class DistributedScheduledTask {
@Autowired
private DistributedLockService lockService;
@Scheduled(cron = "0 */5 * * * ?")
public void distributedTask() {
String lockKey = "distributed_task_lock";
if (lockService.tryLock(lockKey, 300)) { // 锁定5分钟
try {
// 执行任务
System.out.println("获取分布式锁,执行任务");
// 业务逻辑...
} finally {
lockService.unlock(lockKey);
}
} else {
System.out.println("未获取到锁,跳过执行");
}
}
}
总结对比
| 方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| Timer | 简单易用 | 单线程,任务阻塞 | 简单的单机任务 |
| ScheduledExecutorService | 线程池管理,更灵活 | 配置相对复杂 | 需要精细控制的定时任务 |
| Spring @Scheduled | 配置简单,集成方便 | 功能相对基础 | Spring项目中的常规定时任务 |
| Quartz | 功能强大,支持集群 | 配置复杂,依赖多 | 企业级复杂调度需求 |
| Spring + Quartz | 结合两者优势 | 配置较复杂 | 需要Quartz功能的Spring项目 |
推荐使用顺序:Spring @Scheduled → ScheduledExecutorService → Quartz,根据项目复杂度选择合适的方案。

浙公网安备 33010602011771号