Java Timer 定时任务调度详解
Timer 是 Java 原生提供的定时任务调度工具,虽然功能相对简单,但在简单场景下可以满足定时执行任务的需求。本文将详细解析 Timer 的核心组件、调度方式及使用细节。
Timer 核心组件
Timer 框架主要由两个核心类构成:Timer
和 TimerTask
。
TimerTask:任务载体
TimerTask
是一个抽象类,实现了 Runnable
接口,代表一个可以被 Timer 调度的任务。
1 | public abstract class TimerTask implements Runnable { |
注意:虽然 TimerTask
实现了 Runnable
,但它并非独立线程,其 run
方法由 Timer 内部的线程调用(单线程执行)。
Timer:调度器
Timer
负责管理和调度 TimerTask,内部通过一个线程(TimerThread
)执行所有任务,并使用优先级队列(TaskQueue
)存储待执行任务。
核心功能:
- 调度任务(一次性或周期性执行)。
- 管理任务队列(添加、移除、排序)。
- 控制任务执行线程的生命周期。
任务调度方式
Timer 提供了两种主要的调度方法:schedule
(固定时延)和 scheduleAtFixedRate
(固定速率),适用于不同场景。
1. schedule:固定时延调度
特点:任务的下次执行时间 = 上一次任务实际完成时间 + 间隔时间(不受任务执行耗时影响,会顺延)。
方法定义:
1 | // 延迟 delay 毫秒后执行一次 |
示例:
1 | Timer timer = new Timer(); |
执行结果(时间间隔为上次完成 + 2 秒):
1 | 任务执行:10:00:01 // 首次执行(延迟 1 秒) |
2. scheduleAtFixedRate:固定速率调度
特点:任务的下次执行时间 = 上一次任务计划执行时间 + 间隔时间(尽可能保证固定频率,即使任务执行耗时超过间隔)。
方法定义:
1 | // 延迟 delay 毫秒后,以 period 为周期固定速率执行 |
示例:(复用上面的任务代码,仅修改调度方法)
1 | timer.scheduleAtFixedRate(new TimerTask() { ... }, 1000, 2000); |
执行结果(时间间隔为上次计划时间 + 2 秒):
1 | 任务执行:10:00:01 // 首次执行(计划时间) |
注意:如果任务执行耗时超过周期,会导致任务 “追赶执行”(上一个未完成,下一个已触发,会在当前任务结束后立即执行)。
任务管理方法
1. cancel ():取消 Timer 所有任务
1 | public void cancel() { |
作用:
- 终止 Timer 线程,不再执行任何任务(包括已调度但未执行的任务)。
- 已执行的任务不受影响。
2. purge ():清理已取消的任务
1 | public int purge() { |
作用:释放已取消任务占用的资源,优化队列性能。
Timer 的局限性
- 单线程执行:所有任务由 Timer 内部的单个线程执行,若某个任务耗时过长,会阻塞后续任务(即使到了执行时间)。
- 异常终止风险:若任务执行时抛出未捕获异常,Timer 线程会直接终止,导致所有后续任务失效。
- 时间精度低:依赖系统时间,且调度精度受线程调度影响(毫秒级,但实际可能有偏差)。
- 不支持复杂场景:如任务依赖、动态调整周期、分布式调度等,需依赖 Quartz、ScheduledExecutorService 等工具。
使用建议
- 简单场景:可使用 Timer(如定时清理临时文件、简单的周期性任务)。
- 复杂场景:推荐使用
ScheduledExecutorService
(JUC 提供,支持多线程、异常处理更完善)或第三方框架(如 Quartz)。 - 避免耗时任务:若必须使用 Timer,确保任务执行时间远小于调度周期,避免阻塞。
v1.3.10