Timer 兩大調度模式
| 模式 | 方法簽名 | 特性 | 適用場景 |
| 固定延遲 | schedule(task, delay)
schedule(task, delay, period) | 下一次執行時間 = 上一次**實際完成時間** + period。若任務耗時長,間隔自動拉大。 | 輕量級、不嚴格要求頻率的後台清理、同步。 |
| 固定頻率 | scheduleAtFixedRate(task, delay, period) | 下一次執行時間 = 上一次**理論開始時間** + period。若任務延遲,Timer 會嘗試「追趕」壓縮後續間隔。 | 心跳檢測、即時採樣、嚴格週期業務。 |
基礎範例:啟動、停止、動態修改參數
public class TimerDemo {
public static void main(String[] args) throws IOException {
Timer timer = new Timer();
MyTask task1 = new MyTask("Task-1");
MyTask task2 = new MyTask("Task-2");
timer.schedule(task1, 1000, 2000); // 1s 後啟動,每 2s
timer.scheduleAtFixedRate(task2, 2000, 3000); // 2s 後啟動,每 3s 固定頻率
// 控制台指令互動
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String line;
while ((line = in.readLine()) != null) {
if (line.startsWith("cancel-1")) task1.cancel();
else if (line.startsWith("cancel-2")) task2.cancel();
else if (line.startsWith("cancel-all")) { timer.cancel(); break; }
else task1.setMsg(line); // 動態修改任務行為
}
}
static class MyTask extends TimerTask {
private String msg = "^_^";
public void run() { System.out.println(msg); }
public void setMsg(String m) { msg = m; }
}
}
關鍵 API 深度解析
TimerTask.cancel():取消**單個任務**未來執行,已在執行的不受影響。回傳 boolean 表示是否成功取消 (尚未執行過)。
Timer.cancel():取消**所有任務**,釋放 Timer 內部執行緒,**不可重用**,後續 schedule 拋 IllegalStateException。
TimerTask.scheduledExecutionTime():取得**理論應執行時間** (毫秒),可用於計算漂移、補償邏輯。
Timer.purge():從佇列移除已取消任務,釋放記憶體 (大量動態增刪任務時調用)。
常見坑與對策
| 問題 | 原因 | 解決 |
| 任務拋出未捕獲異常 → Timer 執行緒死亡 → 所有任務停止 | Timer 單執行緒循環,異常向上傳播終止循環 | run() 內部 try-catch(Exception e){log} 吞掉所有異常 |
| scheduleAtFixedRate 追趕導致疊併執行 | 任務耗時 > period,Timer 立即排程下一次 | 任務內加 synchronized 或改用 ScheduledExecutorService |
| JVM 關閉前任務未完成 | Timer 執行緒非 Daemon (預設) | new Timer(true) 建立 Daemon Timer,或關閉鉤子呼叫 timer.cancel() |
| 大量任務 (10k+) 效能下降 | 單執行緒輪詢 TaskQueue (鏈表/堆) | 遷移至 ScheduledThreadPoolExecutor |
現代替代:ScheduledExecutorService (Java 5+)
ScheduledExecutorService ses = Executors.newScheduledThreadPool(2);
ses.scheduleAtFixedRate(() -> System.out.println("beat"), 1, 2, TimeUnit.SECONDS);
// 優雅關閉
ses.shutdown();
ses.awaitTermination(10, TimeUnit.SECONDS);
優勢:執行緒池隔離、支援
Future 取消/查狀態、可配置
ThreadFactory (命名、Daemon)、拋異常不影響其他任務。
選型建議
- 簡單工具類、單執行緒、無並發:
Timer 輕量足夠。
- 生產系統、多任務、需監控/優雅關閉/異常隔離:直接上
ScheduledExecutorService。
- 分散式排程、持久化、失敗重試、分片:Quartz、XXL-Job、PowerJob。
Timer 是 Java 早期產物,理解其單執行緒、固定延遲/頻率語義差異,是遷移至現代排程框架的基石。