Skip to content

定时任务面试题

本页只放面试标准回答、常见追问和知识点跳转。详细原理、流程图、代码 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 里包的是什么?任务注册全过程
fixedRatefixedDelay 区别?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 并把状态改回等待;如果没有,就标记完成。这个状态更新失败会导致任务不再触发或重复触发。WAITINGCOMPLETE 怎么理解?完成后的状态更新过程
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、状态、重试次数、下次重试时间和最近错误。补偿任务按状态扫描,成功标记成功,超限进入人工处理。怎么设计失败表?补偿任务设计全过程
定时任务告警怎么设计?告警要包含任务名、环境、失败时间、参数、异常摘要、最近成功时间和处理入口;要有负责人确认、补偿处理和恢复关闭,不是发一条消息就结束。什么是无效告警?告警闭环设计

高频追问清单

  1. Cron 表达式为什么有的 5 位、有的 6 位、有的 7 位?
  2. 定时任务和 MQ 延迟消息怎么选?
  3. 多实例部署时怎么保证只有一个实例执行?
  4. 分布式锁过期导致任务重复执行怎么办?
  5. 任务执行时间超过调度周期怎么办?
  6. 大任务分页为什么不要用深分页?
  7. 定时任务失败重试为什么必须配合幂等?
  8. XXL-JOB 分片广播如何根据分片参数查询数据?
  9. Quartz 的 JDBC JobStore 为什么依赖数据库锁?
  10. 任务调度系统要监控哪些指标?

推荐学习路径

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 调度链路、分片广播、阻塞策略、失败补偿和告警闭环讲完整。