
定时任务是 Java 应用的核心组件之一,无论是系统层面的日志清理、数据备份,还是业务层面的订单超时处理、定时消息推送,都离不开它。一个可靠的定时任务方案能显著提升系统稳定性和可维护性。比如电商系统的 “订单 24 小时未支付自动取消”、金融系统的 “每日对账”,都依赖定时任务精准执行。
Java 原生提供了两种基础方案:Timer和ScheduledExecutorService,无需依赖第三方库,适合简单场景。
原理:Timer内部通过单线程(TimerThread)处理所有任务,任务存储在TaskQueue中按执行时间排序,线程不断从队列取任务执行,周期性任务会重新计算下次执行时间放回队列。
用法示例: 比如实现一个每隔 5 秒输出时间的任务:
import lombok.extern.slf4j.Slf4j;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Date;
@Slf4j
public class TimerExample {
public static void main(String[] args) {
Timer timer = new Timer();
TimerTask task = new TimerTask() {
private int count = 0;
@Override
public void run() {
count++;
log.info("第{}次执行,时间:{}", count, new Date());
if (count >= 5) { // 执行5次后停止
this.cancel();
timer.cancel();
}
}
};
log.info("启动时间:{}", new Date());
timer.schedule(task, 1000, 5000); // 延迟1秒,每隔5秒执行
}
}优缺点:
结论:实际开发中已很少用,推荐用ScheduledExecutorService替代。
原理:JDK1.5 引入的并发工具,基于线程池实现,支持多线程并发执行任务。核心实现类ScheduledThreadPoolExecutor用DelayedWorkQueue(延迟队列)存储任务,按执行时间排序。
核心调度方式:
用法示例:
import lombok.extern.slf4j.Slf4j;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@Slf4j
public class ScheduledExecutorExample {
public static void main(String[] args) {
// 创建2个线程的线程池
ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);
log.info("启动时间:{}", new Date());
// 固定延迟任务:任务执行完隔3秒再执行
Runnable fixedDelayTask = () -> {
log.info("【固定延迟】执行时间:{}", new Date());
try { TimeUnit.SECONDS.sleep(2); } // 模拟耗时2秒
catch (InterruptedException e) { Thread.currentThread().interrupt(); }
};
executor.scheduleWithFixedDelay(fixedDelayTask, 1, 3, TimeUnit.SECONDS);
// 固定速率任务:每隔3秒执行一次
Runnable fixedRateTask = () -> {
log.info("【固定速率】执行时间:{}", new Date());
try { TimeUnit.SECONDS.sleep(2); } // 模拟耗时2秒
catch (InterruptedException e) { Thread.currentThread().interrupt(); }
};
executor.scheduleAtFixedRate(fixedRateTask, 1, 3, TimeUnit.SECONDS);
}
}高级特性:
schedule(Runnable, delay, unit)只执行一次。Callable配合Future获取结果。Future.cancel()取消未执行的任务。优缺点:
适用场景:单机简单定时任务,需多线程并发执行的场景。
Spring 对定时任务的支持更友好,通过注解和配置即可快速实现,底层基于ScheduledExecutorService,但封装更易用。
使用条件:
@EnableScheduling开启支持。@Component等注解被 Spring 管理。void。常用属性:
croncron 表达式定义复杂调度(如0 * * * * ?每分钟执行)。fixedDelay/fixedRate:固定延迟 / 速率(毫秒)。initialDelay首次执行前的延迟时间。示例:
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
@Slf4j
@Component
public class ScheduledTaskService {
// 固定延迟:任务完后隔2秒执行
@Scheduled(fixedDelay = 2000)
public void fixedDelayTask() {
log.info("【fixedDelay】时间:{}", LocalDateTime.now());
}
// cron表达式:每分钟第0秒执行
@Scheduled(cron = "0 * * * * ?")
public void cronTask() {
log.info("【cron】时间:{}", LocalDateTime.now());
}
// 从配置文件取间隔(默认3秒)
@Scheduled(fixedDelayString = "${task.delay:3000}")
public void configTask() {
log.info("【配置任务】时间:{}", LocalDateTime.now());
}
}2. cron 表达式怎么用?
cron 表达式是复杂调度的核心,格式为秒 分 时 日 月 周,每个字段用特殊字符定义规则。
常用特殊字符:
*匹配所有值(如 “分” 字段*表示每分钟)。?“日” 和 “周” 字段用,避免冲突(如0 0 0 * * ?每天 0 点)。/步长(如0/15 * * * * ?每 15 秒执行)。-范围(如9-18表示 9 点到 18 点)。#周字段专用(如3#2表示当月第 2 个周一)。示例:
0 0 8 * * MON-FRI:每周一至周五早 8 点。0 30 12 1 * ?:每月 1 号中午 12:30。0 0/30 9-18 * * ?:9 点到 18 点每 30 分钟一次。默认 Spring 定时任务单线程执行,可配置异步避免阻塞: 步骤:
@EnableAsync开启异步。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
@Configuration
public class TaskExecutorConfig {
@Bean("taskExecutor")
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5); // 核心线程5个
executor.setMaxPoolSize(10); // 最大线程10个
executor.setQueueCapacity(20); // 队列容量20
executor.setThreadNamePrefix("Scheduled-"); // 线程名前缀
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); // 拒绝策略
return executor;
}
}@Async("taskExecutor"):@Async("taskExecutor")
@Scheduled(cron = "0/5 * * * * ?")
public void asyncTask() {
log.info("【异步任务】线程:{},时间:{}",
Thread.currentThread().getName(), LocalDateTime.now());
}4. 动态调整定时任务周期(不重启应用)
Spring Task 本身不支持动态配置,但可结合ScheduledTaskRegistrar和自定义Trigger实现:
核心思路:
Trigger每次执行前获取最新 cron 表达式。taskScheduler.schedule(task, trigger)动态注册任务。单机定时任务在分布式环境下会有重复执行、节点故障丢失任务等问题,需专业分布式框架解决。
核心概念:
Job任务逻辑(实现execute方法)。JobDetail任务元信息(名称、参数等)。Trigger调度规则(CronTrigger/SimpleTrigger)。Scheduler调度核心,协调 Job 和 Trigger。JobStore存储任务信息(内存 / 数据库,分布式用数据库)。用法示例:
@Slf4j
public class SampleJob implements Job {
@Override
public void execute(JobExecutionContext context) {
String param = context.getJobDetail().getJobDataMap().getString("param");
log.info("【Quartz任务】参数:{},时间:{}", param, LocalDateTime.now());
}
}配置 Job 和 Trigger:
@Configuration
public class QuartzConfig {
@Bean
public JobDetail sampleJobDetail() {
JobDataMap map = new JobDataMap();
map.put("param", "Quartz示例任务");
return JobBuilder.newJob(SampleJob.class)
.withIdentity("sampleJob", "group1")
.setJobData(map)
.storeDurably()
.build();
}
@Bean
public Trigger sampleTrigger() {
// 每5秒执行一次
CronScheduleBuilder cron = CronScheduleBuilder.cronSchedule("0/5 * * * * ?");
return TriggerBuilder.newTrigger()
.forJob(sampleJobDetail())
.withIdentity("sampleTrigger", "group1")
.withSchedule(cron)
.build();
}
}分布式配置:
需用数据库存储任务信息(MySQL 可执行tables_mysql.sql脚本建表),并在配置中开启集群:
spring:
quartz:
properties:
org:
quartz:
jobStore:
isClustered: true # 启用集群
clusterCheckinInterval: 15000 # 节点检查间隔15秒
class: org.quartz.impl.jdbcjobstore.JobStoreTX # 数据库存储
scheduler:
instanceId: AUTO # 自动生成实例ID(集群唯一)优缺点:
适用场景:企业级应用,复杂调度需求,分布式环境。
XXL-Job 是大众点评开源的分布式任务调度平台,架构简单(调度中心 + 执行器),易用性强。
架构:
使用步骤:
部署调度中心:
tables_xxl_job.sql建库表。集成执行器到 Spring Boot:
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
<version>2.3.0</version>
</dependency>xxl:
job:
admin:
addresses: http://localhost:8080/xxl-job-admin # 调度中心地址
executor:
appname: demo-executor # 执行器名称
port: 9999 # 端口配置类:
@Configuration
public class XxlJobConfig {
@Bean
public XxlJobSpringExecutor xxlJobExecutor(@Value("${xxl.job.admin.addresses}") String adminAddresses) {
XxlJobSpringExecutor executor = new XxlJobSpringExecutor();
executor.setAdminAddresses(adminAddresses);
executor.setAppname("demo-executor");
executor.setPort(9999);
return executor;
}
}开发任务:
@Slf4j
@Component
public class XxlJobHandler {
// 任务标识:@XxlJob("任务名")
@XxlJob("simpleJob")
public void simpleJob() {
log.info("【XXL-Job】执行时间:{}", LocalDateTime.now());
// 任务逻辑...
XxlJobHelper.handleSuccess("执行成功"); // 返回结果
}
}demo-executor)。0/10 * * * * ?),任务 ID 填@XxlJob注解的名称(simpleJob)。高级特性:
优缺点:
适用场景:分布式系统,需简单易用、可视化管理的场景,中小型项目首选。
技术 | 适用场景 | 核心优势 |
|---|---|---|
Timer | 简单单机任务,低可靠性需求 | 原生 API,极简 |
ScheduledExecutorService | 单机多线程任务,无复杂调度 | 多线程,异常安全 |
Spring Task | Spring 生态单机应用,需 cron | 集成方便,注解易用 |
Quartz | 企业级复杂调度,分布式高可靠 | 功能强,稳定成熟 |
XXL-Job | 分布式系统,需可视化管理 | 易用性高,轻量级 |