定时任务面试题
本页只放面试标准回答、常见追问和知识点跳转。详细原理、流程图、代码 Demo、商业场景和排查方法,请跳到对应知识点页学习。
总览
| 面试题 | 标准回答 | 追问点 | 原理跳转 |
|---|---|---|---|
| 怎么判断定时任务是否真正学懂? | 不能只会写 cron 或 @Scheduled。真正学懂要能从触发时间、调度器、执行器、线程池、幂等、失败重试、执行日志、告警、分片、阻塞策略、补偿和生产排查一路讲下来,并能说明每个环节为什么这样设计、不这样会出什么线上问题。 | 如何证明任务可重跑、可补偿、可观测? | 定时任务从零到精通验收清单 |
| 定时任务解决什么问题? | 定时任务解决系统在指定时间或周期自动执行后台业务的问题,例如关单、对账、报表、补偿、清理和同步。生产级定时任务不只是 cron,还要处理幂等、日志、重试、告警、超时、分片和故障恢复。 | 为什么不能只写 cron? | 定时任务总览 |
| 定时任务常见方案有哪些? | 常见方案有 Linux crontab、Spring @Scheduled、Quartz、XXL-JOB、MQ 延迟消息和 K8s CronJob。简单本地任务用 @Scheduled,Java 应用内持久化调度用 Quartz,微服务统一治理用 XXL-JOB,单条数据到期触发可用延迟消息。 | 订单关单怎么选? | 常见调度方案 |
| 定时任务为什么必须幂等? | 因为任务可能重复触发、失败重试、多实例并发、服务重启补偿。幂等保证同一批数据重复处理也不会造成重复扣款、重复发券、重复关单。常见做法是更新时带状态条件、唯一索引、防重表、业务流水号。 | 不幂等会怎样? | 幂等是第一原则 |
Spring Scheduled
| 面试题 | 标准回答 | 追问点 | 原理跳转 |
|---|---|---|---|
@Scheduled 原理是什么? | Spring 启动时通过 @EnableScheduling 开启定时任务基础设施,由 ScheduledAnnotationBeanPostProcessor 扫描 Bean 方法上的 @Scheduled,解析 cron、fixedRate、fixedDelay,把方法包装成任务注册到本地调度器,到点后由线程池调用目标方法。 | 注解什么时候被扫描? | 启动扫描全过程 |
@Scheduled 方法为什么必须是 Spring Bean? | Spring 只能扫描容器里的 Bean。普通类即使写了 @Scheduled,如果没有 @Component 或 @Bean 注册,Spring 不会管理它,也不会把它注册成定时任务。 | 为什么编译不报错但任务不跑? | 谁负责扫描 @Scheduled |
@Scheduled 方法为什么通常不能带参数? | 它不是被 HTTP 或 MQ 调用,而是由本地调度器到点反射调用。调度器只知道调用哪个 Bean 的哪个方法,不知道该传什么业务参数。需要参数时应从配置、数据库或任务内部读取。 | 动态参数怎么传? | 为什么 @Scheduled 方法不能随便写参数 |
Spring 怎么注册一个 @Scheduled 任务? | Spring 扫描到注解后读取触发属性,根据 cron 创建 CronTrigger,根据 fixedRate/fixedDelay 创建固定任务,再把目标方法包装成 Runnable 注册到任务调度器。 | Runnable 里包的是什么? | 任务注册全过程 |
fixedRate 和 fixedDelay 区别? | fixedRate 按上一次开始时间加间隔计算下一次,强调频率,任务慢时可能堆积或重叠;fixedDelay 按上一次结束时间加延迟计算下一次,强调间隔,更适合补偿类任务。 | 任务执行超过周期会怎样? | 触发时间计算过程 |
| Cron 在 Spring 里有什么坑? | Spring Cron 常见是 6 位,Linux crontab 通常是 5 位;还要注意时区、整点任务洪峰和应用停机期间错过触发不会自动完整补偿。 | 为什么复制 crontab 表达式会错? | Cron 为什么适合固定业务时间 |
@Scheduled 到点后怎么执行? | 触发时间到达后,调度器取出任务 Runnable,提交到调度线程池,由线程调用目标方法。方法抛异常时通常只进入错误处理和日志,不会自动重试,下一次到点再执行。 | 失败了会自动重试吗? | 线程执行全过程 |
@Scheduled 任务异常怎么处理? | 不能只依赖日志。任务内部应该捕获异常,记录业务参数、耗时和错误原因,核心任务还要告警并写失败批次,便于后续补偿。 | ES 同步失败怎么发现? | 异常为什么不能只靠日志 |
@Scheduled 线程池怎么配置? | 生产环境应显式配置 ThreadPoolTaskScheduler,设置线程数、线程名前缀、停机等待策略。线程数要根据任务耗时、数据库压力和下游限流估算,不是越大越好。 | 线程池太小会怎样? | 线程池配置原理 |
多实例部署后 @Scheduled 有什么问题? | 每个实例都有自己的 Spring 容器和本地调度器,因此同一个任务会在每个实例都注册并到点执行。解决方式是任务幂等、分布式锁、固定实例执行,或改用 XXL-JOB。 | Redis 锁过期会怎样? | 多实例重复执行的完整过程 |
哪些 @Scheduled 任务可以多实例都跑? | 本地缓存刷新、本机指标采集、清理本机临时文件可以多实例都跑;订单关单、发券、对账、结算不适合多实例重复执行,因为会重复扫描、重复发放或重复生成结果。 | 如何判断能不能重复? | 哪些任务可以多实例都跑 |
| 加了分布式锁为什么还要幂等? | 锁可能因为超时、GC、网络抖动、进程停顿而失效,导致另一个实例拿到锁并处理同一批数据。锁只能减少并发,最终正确性必须靠状态条件、唯一索引、业务流水等幂等设计保证。 | 关单 SQL 为什么带状态? | 用锁后为什么仍然要幂等 |
@Scheduled 适合生产吗? | 适合简单、低频、影响面小的本地任务。只要涉及多实例、执行日志、控制台、分片、告警、人工重跑、失败治理,就不应该只依赖 @Scheduled。 | 什么时候必须换 XXL-JOB? | Spring 定时任务 |
Quartz
| 面试题 | 标准回答 | 追问点 | 原理跳转 |
|---|---|---|---|
| Quartz 是什么? | Quartz 是 Java 生态成熟的任务调度框架。它把任务定义、触发规则、持久化、错过触发和集群协调抽象出来,适合 Java 应用内需要持久化和动态管理的定时任务。 | 和 @Scheduled 区别? | Quartz |
| Quartz 核心组件有哪些? | 核心组件包括 Scheduler、Job、JobDetail、Trigger、JobStore 和线程池。Job 是业务逻辑,JobDetail 是任务元数据,Trigger 决定何时触发,JobStore 保存任务和状态,Scheduler 负责调度执行。 | Trigger 有哪些类型? | 核心概念 |
| Quartz 启动后怎么开始调度? | Spring Boot 先读取 spring.quartz 配置,创建 SchedulerFactoryBean 和 Scheduler,再初始化 JobStore、线程池,注册 JobDetail 和 Trigger,最后启动调度线程扫描到期 Trigger。任何一步失败都会导致任务不触发。 | Scheduler 启动了但任务没跑查哪里? | 启动全过程 |
| JobDetail 和 Trigger 为什么要分开? | JobDetail 描述任务是谁、参数是什么;Trigger 描述什么时候触发。这样同一个 Job 可以绑定多个 Trigger,例如同一个报表 Job 既可以生成日报,也可以生成月报。分开后任务定义和触发规则可以独立管理。 | 随机任务名有什么风险? | 任务注册全过程 |
| Quartz 到点后如何抢任务? | 调度线程查询 nextFireTime 已到期的 Trigger,集群场景下通过数据库锁和 Trigger 状态抢占,抢到后把 Trigger 标记为 ACQUIRED,再提交给本机线程池执行。没有锁和状态更新就可能多节点重复执行。 | ACQUIRED 卡住说明什么? | Trigger 抢占全过程 |
| Quartz 执行 Job 的过程是什么? | Quartz 抢到 Trigger 后创建执行壳,实例化 Job,构造 JobExecutionContext,调用监听器,执行 execute 方法,然后根据结果更新 Trigger 状态和下一次触发时间。排查延迟可比较计划触发时间和实际触发时间。 | Job 里能不能用成员变量保存进度? | 执行全过程 |
| Quartz 执行完任务后做什么? | 执行完成后 Quartz 会判断 Trigger 是否还有下一次触发。如果有,就计算新的 nextFireTime 并把状态改回等待;如果没有,就标记完成。这个状态更新失败会导致任务不再触发或重复触发。 | WAITING、COMPLETE 怎么理解? | 完成后的状态更新过程 |
| Quartz 集群怎么避免重复执行? | Quartz 集群通常使用 JDBC JobStore。多个节点共享同一套 Quartz 表,通过节点心跳、Trigger 状态和数据库锁协调,只有抢到 Trigger 的节点执行任务。 | 数据库慢会怎样? | 为什么 Quartz 能支持集群 |
| Quartz 常见表有什么用? | QRTZ_JOB_DETAILS 看任务定义,QRTZ_TRIGGERS 看触发器状态,QRTZ_CRON_TRIGGERS 看 Cron,QRTZ_FIRED_TRIGGERS 看已获取或执行中的 Trigger,QRTZ_SCHEDULER_STATE 看节点心跳。 | 任务不触发先查哪张表? | Quartz 表怎么看 |
| Quartz 节点宕机后怎么恢复? | 集群节点会定期写心跳。某节点宕机后,其他节点发现它超过心跳阈值,会恢复它未完成的 Trigger,后续重新调度。但 Quartz 只恢复调度状态,业务是否重复处理仍要靠幂等保证。 | clusterCheckinInterval 怎么配? | 集群故障恢复过程 |
| Misfire 是什么? | Misfire 是任务错过了原本触发时间,例如应用停机、线程池满、GC 卡顿、数据库锁等待。生产中必须明确错过后是立即补跑、跳过、还是按默认策略处理,否则恢复后可能漏执行或瞬间补跑压垮系统。 | 订单关单用哪种策略? | Misfire 是什么 |
| Quartz 怎么判断 Misfire? | Quartz 会比较当前时间和 Trigger 的 nextFireTime,如果当前时间明显晚于 nextFireTime 并超过 Misfire 阈值,就按 Trigger 配置的 Misfire 策略处理,例如立即补跑一次或跳过等待下一次。 | 为什么不能无脑补跑? | Misfire 判断过程 |
@DisallowConcurrentExecution 能解决什么? | 它禁止同一个 JobDetail 并发执行,适合对账、报表这类不能同时跑两份的任务。但它不能替代业务幂等,也不能阻止不同 JobDetail 或不同系统同时改同一份业务数据。 | 它和分布式锁有什么区别? | 并发控制过程 |
| Quartz 和 XXL-JOB 怎么选? | Quartz 适合应用内持久化调度和动态任务;XXL-JOB 更适合微服务统一任务治理,提供控制台、执行日志、路由、分片、失败重试和告警。任务多、团队多、服务多时优先 XXL-JOB。 | Quartz 有没有控制台? | 和其他方案对比 |
XXL-JOB
| 面试题 | 标准回答 | 追问点 | 原理跳转 |
|---|---|---|---|
| XXL-JOB 架构是什么? | XXL-JOB 由调度中心、执行器、任务 Handler 和调度数据库组成。调度中心负责管理任务、计算触发时间、选择执行器并下发调度请求;执行器注册到调度中心,收到请求后执行本地 JobHandler 并回传日志和结果。 | 调度中心挂了怎么办? | XXL-JOB |
| 执行器启动后怎么注册到 Admin? | 业务服务启动时创建 XxlJobSpringExecutor,扫描 @XxlJob 方法形成 Handler 映射,启动执行器内置 HTTP 服务,然后用 appname 和地址向 Admin 注册并持续心跳。Admin 后续按 appname 查在线执行器。 | appname 写错会怎样? | 启动和注册全过程 |
| Admin 是怎么发现到点任务的? | Admin 后台调度线程扫描数据库中的任务配置,根据 cron 和下次触发时间找出到期任务,生成调度日志,查询执行器地址,按路由策略下发触发请求,并更新下一次触发时间。 | 为什么先生成调度日志? | Admin 调度扫描全过程 |
| XXL-JOB 执行流程是什么? | 任务到点后,调度中心读取任务配置,按路由策略选择执行器,通过 HTTP 调用执行器,执行器找到 JobHandler 执行业务逻辑,然后把执行日志和结果回调给调度中心。 | 执行器离线怎么办? | 执行流程 |
| XXL-JOB 路由选择过程是什么? | Admin 先按 appname 找到在线执行器列表,再根据路由策略选择一台或多台执行器。轮询是均衡压力,故障转移会探测可用节点,分片广播会让所有在线执行器都执行一次。 | 路由能保证业务不重复吗? | 路由选择全过程 |
| 执行器收到请求后做什么? | 执行器收到 Admin 的 HTTP 调度请求后,会校验 accessToken,解析 jobId、handler 和参数,查找 JobHandler,判断阻塞策略,再提交任务线程执行业务,最后写日志并回调 Admin。 | JobHandler 找不到怎么排查? | 执行器接收请求全过程 |
| XXL-JOB 日志是怎么回传的? | Admin 先创建触发日志,执行器执行业务时用 XxlJobHelper.log 写本地执行日志,任务结束后执行器回调 Admin 更新结果,控制台再把触发状态和执行结果展示出来。 | 控制台看不到日志查哪里? | 日志回调全过程 |
| XXL-JOB 路由策略有哪些? | 常见路由策略有第一个、最后一个、轮询、随机、一致性 Hash、最不经常使用、最近最久未使用、故障转移、忙碌转移、分片广播。生产中根据任务是否有状态、是否需要分片、是否要求高可用来选择。 | 分片广播怎么用? | 路由策略怎么选 |
| 分片广播是什么? | 分片广播是调度中心把同一个任务下发给所有在线执行器,每个执行器拿到自己的分片序号和总分片数,只处理属于自己的数据范围。适合大批量扫描、报表、补偿任务。 | 如何避免重复处理? | 分片广播执行过程 |
| 阻塞策略怎么选? | 阻塞策略解决“上一次还没跑完,下一次又来了”的问题。串行适合不能并发的任务,丢弃后续适合允许跳过的高频任务,覆盖之前适合只保留最新结果的任务。关键是结合业务一致性选择。 | 为什么不能无脑覆盖旧任务? | 阻塞策略执行过程 |
| 失败重试和告警怎么设计? | 对临时网络抖动可以设置有限重试,对业务错误不能盲目重试。任务失败要记录参数、异常、耗时和批次号,并通过企业微信、短信或监控平台告警。重试必须配合幂等。 | 重试会导致重复执行吗? | 失败重试全过程 |
商业场景
| 面试题 | 标准回答 | 追问点 | 原理跳转 |
|---|---|---|---|
| 订单超时关闭怎么设计? | 可以用延迟消息做主链路,到期触发关单;再用低频定时任务扫描漏网订单做补偿。更新订单时必须带 status = WAIT_PAY 条件,防止用户刚支付成功又被关单。 | 为什么不能一次扫全表? | 订单超时关闭示例 |
| 对账任务怎么设计? | 对账任务应按账期和渠道生成批次,拉取渠道账单,与本地订单按订单号、金额、状态比对,生成差异单。不要直接改账务数据,应该先留痕,再补偿。 | 失败后怎么重跑? | Quartz 商业场景 |
| ES 同步失败怎么补偿? | 主链路通常用 MQ 同步 ES,失败时记录失败表;定时任务按状态、重试次数分页扫描失败记录,重新同步 ES,成功后标记成功,失败增加重试次数并告警。 | ES 一直失败怎么办? | ES 同步补偿 |
| 大批量任务为什么要分片? | 单机一次处理太多数据会导致 SQL 慢、锁时间长、内存高、下游被打爆。分片可以让多个执行器按规则处理不同数据范围,提高吞吐,并降低单点耗时。 | 分片后怎么保证不漏不重? | 任务堆积排查全过程 |
排查题
| 面试题 | 标准回答 | 追问点 | 原理跳转 |
|---|---|---|---|
| 定时任务不触发怎么排查? | 先确认时间和 Cron,再区分框架:@Scheduled 查 @EnableScheduling、Bean 扫描和线程池;Quartz 查 Scheduler、Trigger 和 QRTZ_* 表;XXL-JOB 查任务状态、Admin 调度日志和执行器注册。 | Cron 字段数量有什么坑? | 任务不触发排查全过程 |
| 任务跑了但没效果怎么排查? | 先确认是否查到数据,再看更新行数、事务是否提交、后续事件是否发送、下游是否处理成功。日志要记录 scanned、success、skipped、failed,不能只写 success。 | scanned 大于 0 但 closed 为 0 说明什么? | 任务跑了但没效果排查全过程 |
| 任务重复执行怎么排查? | 先查调度日志是否多次触发,再查是否多实例本地调度、失败重试、人工补偿重复点击、锁过期、分片条件写错,最后检查业务幂等是否缺失。 | 重复执行已经造成脏数据怎么办? | 重复执行排查全过程 |
| 任务越跑越慢怎么办? | 先拆分耗时:查询耗时、单条处理耗时、下游接口耗时、事务提交耗时和日志耗时;再看 SQL 执行计划、批次大小、索引、锁等待、下游超时和限流。 | 为什么不能只扩机器? | 执行慢排查全过程 |
| 任务堆积怎么排查? | 先区分调度堆积还是数据堆积。调度堆积看任务耗时是否超过周期;数据堆积看新增速度和处理速度。处理方式包括调大周期、拆任务、分片、优化 SQL、限流下游。 | 怎么计算多久能清空? | 任务堆积排查全过程 |
| 任务失败后怎么补偿? | 失败要写入补偿表,记录业务类型、业务 ID、状态、重试次数、下次重试时间和最近错误。补偿任务按状态扫描,成功标记成功,超限进入人工处理。 | 怎么设计失败表? | 补偿任务设计全过程 |
| 定时任务告警怎么设计? | 告警要包含任务名、环境、失败时间、参数、异常摘要、最近成功时间和处理入口;要有负责人确认、补偿处理和恢复关闭,不是发一条消息就结束。 | 什么是无效告警? | 告警闭环设计 |
高频追问清单
- Cron 表达式为什么有的 5 位、有的 6 位、有的 7 位?
- 定时任务和 MQ 延迟消息怎么选?
- 多实例部署时怎么保证只有一个实例执行?
- 分布式锁过期导致任务重复执行怎么办?
- 任务执行时间超过调度周期怎么办?
- 大任务分页为什么不要用深分页?
- 定时任务失败重试为什么必须配合幂等?
- XXL-JOB 分片广播如何根据分片参数查询数据?
- Quartz 的 JDBC JobStore 为什么依赖数据库锁?
- 任务调度系统要监控哪些指标?
推荐学习路径
mermaid
flowchart TD
A["先学定时任务总览"] --> B["掌握 @Scheduled"]
B --> C["理解多实例重复执行"]
C --> D["学习 Quartz 持久化和 Misfire"]
D --> E["学习 XXL-JOB 架构和路由"]
E --> F["学习分片、重试、阻塞策略"]
F --> G["掌握生产排查"]
G --> H["用面试题反向检验"]深度验收跳转
如果面试官继续追问原理,不要只停留在“我会 XXL-JOB”。按 定时任务从零到精通验收清单 回到知识点页,把触发计算、多实例重复执行、幂等、Quartz Misfire、XXL-JOB 调度链路、分片广播、阻塞策略、失败补偿和告警闭环讲完整。
