定时器详解
一、定时器概述
什么是定时器?
Java定时器(Timer)是一种用于在指定时间或周期性间隔执行任务的工具,适用于定时任务调度、轮询检测、延迟操作等场景。它通过后台线程实现对任务的自动化调度管理。
定时器也是软件开发中的一个重要组件. 类似于一个 "闹钟". 达到一个设定的时间之后, 就执行某个指定 好的代码.
核心类与接口
java.util.Timer
单线程任务调度器,通过schedule()
方法安排任务。-
java.util.TimerTask
抽象类,需实现run()
方法定义具体任务逻辑。 -
ScheduledExecutorService
更现代的替代方案(Java 5+),基于线程池,提供更灵活的调度控制
二、Java标准库中的Timer类
Timer类核心机制
Java标准库中的java.util.Timer
类用于实现定时任务调度,其核心特点是单线程任务队列管理。所有通过schedule
方法提交的任务都会进入同一个线程的任务队列,按预定时间顺序执行。
schedule方法
方法签名说明
// 单次执行
void schedule(TimerTask task, long delay)// 固定间隔周期性执行(基于前次执行结束时间)
void schedule(TimerTask task, long delay, long period)// 固定速率周期性执行(基于首次执行开始时间)
void scheduleAtFixedRate(TimerTask task, long delay, long period)
参数详解
参数 | 类型 | 说明 |
---|---|---|
task | TimerTask | 具体任务对象,需继承并实现run()方法 |
delay | long | 首次执行延迟时间(单位:毫秒) |
period | long | 周期性任务间隔时间(仅限多次执行任务,单位:毫秒) |
使用示例
基础单次任务
Timer timer = new Timer();
timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("延迟2秒执行: " + new Date());}
}, 2000); // 2000毫秒后执行
周期性任务(固定间隔)
timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("每隔3秒执行: " + new Date());try {Thread.sleep(1000); // 模拟任务耗时} catch (InterruptedException e) {e.printStackTrace();}}
}, 0, 3000); // 立即开始,每次间隔3秒(基于任务结束时间)
周期性任务(固定速率)
timer.scheduleAtFixedRate(new TimerTask() {@Overridepublic void run() {System.out.println("固定速率执行: " + new Date());}
}, 0, 3000); // 立即开始,严格每3秒执行一次
关键注意事项
任务对象要求
- 必须继承
TimerTask
抽象类 - 需要重写
run()
方法(无返回值) - 推荐任务执行时间短于间隔周期
执行特性对比
执行模式 | 特点 |
---|---|
单次执行 | 执行后自动从队列移除 |
schedule() | 周期性任务间隔基于前次任务结束时间计算 |
scheduleAtFixedRate() | 严格按初始时间计划执行,适合需要累积补偿的场景 |
阻塞风险示例
Timer timer = new Timer();
timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("开始长时间任务: " + new Date());try {Thread.sleep(5000); // 任务耗时超过间隔时间} catch (InterruptedException e) {e.printStackTrace();}}
}, 0, 2000); // 预期每2秒执行,实际间隔变为5秒以上
三、实现定时器
// 定时任务调度框架核心类/*** 定时任务实体类,实现Comparable接口用于优先级队列排序*/
class Tier implements Comparable<Tier> {private Runnable command; // 待执行的任务private long time; // 任务执行时间戳(毫秒)/*** 任务构造函数* @param command 待执行的任务逻辑* @param after 延迟执行时间(毫秒)*/public Tier(Runnable command, long after) {this.command = command;this.time = System.currentTimeMillis() + after; // 计算绝对执行时间}/*** 任务执行方法*/@Overridepublic void run() {command.run();}/*** 比较器实现(按执行时间排序)*/@Overridepublic int compareTo(Tier o) {return Long.compare(this.time, o.time); // 时间早的任务优先执行}
}/*** 工作线程类,负责从队列获取并执行任务*/
class Worker extends Thread {private PriorityQueue<Tier> queue = new PriorityQueue<>(); // 优先级任务队列/*** 线程运行主逻辑*/@Overridepublic void run() {while (true) {try {synchronized (queue) {// 队列为空时等待while (queue.isEmpty()) {queue.wait();}// 获取队首任务Tier task = queue.peek();long current = System.currentTimeMillis();long remain = task.time - current;// 未到执行时间时继续等待if (remain > 0) {queue.wait(remain);} else {// 取出并执行任务task = queue.poll();task.run();}}} catch (InterruptedException e) {// 处理线程中断break; }}}/*** 添加新任务到队列*/public void schedule(Runnable command, long after) {synchronized (queue) {queue.offer(new Tier(command, after));queue.notify(); // 唤醒等待线程}}
}/*** 定时器主类*/
public class Timer {private Worker worker; // 工作线程实例public Timer() {worker = new Worker();worker.start(); // 启动工作线程}/*** 调度任务方法* @param command 任务逻辑* @param after 延迟时间(毫秒)*/public void schedule(Runnable command, long after) {worker.schedule(command, after);}/*** 示例使用*/public static void main(String[] args) {Timer timer = new Timer();// 调度延迟任务(2000ms后执行)timer.schedule(() -> System.out.println("Task 1 executed"), 2000);// 调度周期性任务(首次延迟1000ms,之后间隔3000ms)timer.schedule(new Runnable() {@Overridepublic void run() {System.out.println("Periodic task executed");// 重新调度实现周期性timer.schedule(this, 3000); }}, 1000);}
}
-
核心设计思想
通过优先级队列实现时间排序,Worker线程智能等待,同时使用wait/notify机制优化资源使用 -
线程安全处理
在队列操作时使用synchronized同步块,确保多线程环境下的数据一致性 -
延迟计算优化
long remain = task.time - current;
精确计算剩余等待时间,避免无效轮询 -
周期性任务实现技巧
在任务内部重新调用schedule方法,形成循环调度链 -
中断处理机制
catch代码块中处理InterruptedException,保证线程可被正常终止
四、总结
Java定时器是任务调度的核心工具,理解其原理与差异至关重要。对于简单需求,Timer
足够便捷;高并发或复杂调度场景建议采用ScheduledExecutorService
。此外,第三方库如Quartz、Spring Task提供了更强大的分布式调度能力,可根据项目需求扩展。