Timer是什么?—— Java世界的机械发条
想象一个老式的发条闹钟:
- 你设定好时间(schedule)
- 到点就会"叮铃铃"响(执行任务)
- 可以设置单次或重复提醒
Java的Timer
类就是这样一个简单可靠的定时任务工具,自JDK1.3就存在的老牌调度器!
Timer的核心用法三连
1. 单次定时任务
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println("3秒后执行,只执行一次!");
}
}, 3000); // 3000毫秒=3秒后执行
2. 固定延迟重复执行
// 首次2秒后执行,之后每次执行完隔1秒再执行
timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println("执行时间:" + new Date());
}
}, 2000, 1000);
3. 固定频率重复执行
// 首次立即执行,之后每1秒执行一次(不管任务执行多久)
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
System.out.println("固定频率执行:" + System.currentTimeMillis());
}
}, 0, 1000);
Timer的三大特点
-
单线程执行
所有任务都在同一个后台线程顺序执行
→ 一个任务卡住会影响其他任务 -
精确性一般
依赖系统时钟,不保证毫秒级精度
→ 适合对时间不敏感的任务 -
异常会终止
任务抛出未捕获异常时,整个Timer会停止
→ 记得用try-catch包裹任务代码
Timer vs ScheduledThreadPoolExecutor
特性 | Timer | ScheduledThreadPoolExecutor |
---|---|---|
诞生时间 | JDK 1.3 (2000年) | JDK 1.5 (2004年) |
线程模型 | 单线程 | 多线程 |
异常处理 | 异常会导致Timer终止 | 只影响当前任务 |
任务堆积 | 长时间任务会导致延迟 | 线程池可配置处理策略 |
时间精度 | 依赖系统时钟 | 更高精度 |
适用场景 | 简单的轻量级定时任务 | 复杂的生产环境调度 |
5个实际使用案例
1. 简单的超时控制
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println("操作超时!");
System.exit(0);
}
}, 30_000); // 30秒超时
2. 每日提醒功能
// 计算到明天0点的时间差
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.DAY_OF_YEAR, 1);
calendar.set(Calendar.HOUR_OF_DAY, 0);
// ...其他字段清零
new Timer().scheduleAtFixedRate(dailyTask,
calendar.getTime(),
24 * 60 * 60 * 1000); // 每天执行
3. 延迟初始化
// 应用启动5秒后初始化非关键组件
new Timer().schedule(initTask, 5000);
4. 简单的重试机制
Timer timer = new Timer();
timer.schedule(new TimerTask() {
int retryCount = 0;
@Override
public void run() {
if (doSomething() || ++retryCount >= 3) {
timer.cancel(); // 成功或重试3次后停止
}
}
}, 0, 1000); // 立即开始,每秒重试一次
5. 资源定时释放
// 10分钟后自动关闭数据库连接
new Timer().schedule(new TimerTask() {
@Override
public void run() {
if (!connection.isClosed()) {
connection.close();
}
}
}, 10 * 60 * 1000);
Timer的三大缺陷及解决方案
-
单线程阻塞问题
→ 解决方案:改用ScheduledThreadPoolExecutor
-
系统时钟敏感
→ 解决方案:系统时间修改时,用scheduleAtFixedRate
会有问题 -
异常传播问题
→ 解决方案:每个任务都加try-catchtimer.schedule(new TimerTask() { @Override public void run() { try { riskyOperation(); } catch (Exception e) { logger.error("任务执行失败", e); } } }, delay);
最佳实践建议
-
简单场景才用Timer
- 少量不重要的定时任务
- 测试代码或demo程序
-
生产环境推荐替代品
// 更现代的替代方案 ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
-
总要记得取消
Timer timer = new Timer(); // ...使用timer timer.cancel(); // 不再需要时调用
-
命名你的Timer线程
Timer timer = new Timer("订单超时检查线程");
一句话总结
Java Timer就像你抽屉里的那个老式机械闹钟——简单可靠但功能有限,适合不重要的提醒任务。对于关键业务,还是换上"ScheduledThreadPoolExecutor"这个智能电子闹钟更稳妥! ⏰➡️⏱️