Java 提供 java.util.Timer 與 java.util.TimerTask 實現基礎排程功能。雖然現代專案多採用 ScheduledExecutorService 或 Spring @Scheduled,但理解 Timer 基礎機制對維護舊系統、輕量級任務仍有價值。本文詳細解析兩類別用法、排程模式差異與實戰範例。
Runnable 的抽象類別,封裝實際業務邏輯(run() 方法)
// 首次延遲 1 秒執行,之後每 2 秒執行一次
timer.schedule(task, 1000, 2000);
// 指定日期首次執行,之後每 3 分鐘執行
timer.schedule(task, firstTime, 3 * 60 * 1000);
特性:若任務執行時間超過間隔,下一次執行會順延;不會補償過去遲到的執行。
// 立即啟動,每 2 秒執行
timer.scheduleAtFixedRate(task, 0, 2000);
// 指定過去時間啟動,會嘗試補償漏執行的次數
timer.scheduleAtFixedRate(task, pastDate, 3 * 60 * 1000);
特性:嚴格維持頻率,若發現落後會嘗試追趕(連續執行多次),適合對時間敏感的任務。
假設目前 14:17,排程設定 14:10 開始、每 3 分鐘執行:
| 模式 | 實際執行時間 | 下一次排程 |
|---|---|---|
| scheduleAtFixedRate | 立即連續執行 3 次(補 14:10、14:13、14:16) | 14:19(從基準時間推算) |
| schedule | 立即執行 1 次 | 14:20(從實際執行時間推算) |
public class MyTask extends TimerTask {
@Override
public void run() {
System.out.println("任務執行:" + new Date());
// 業務邏輯:發送報表、清理快取、資料同步等
}
}
public class TimerDemo {
public static void main(String[] args) {
Timer timer = new Timer();
// 1 秒後啟動,每 2 秒執行一次
timer.schedule(new MyTask(), 1000, 2000);
}
}
public class SearchRun {
public static void startRun() {
Timer timer = new Timer();
TimerTask task = new TimerTask() {
@Override
public void run() {
System.out.println("開始執行排程任務");
// 呼叫服務層方法
}
};
// 固定頻率:從現在開始,每 2 秒
timer.scheduleAtFixedRate(task, new Date(), 2000);
}
public static void main(String[] args) {
startRun();
}
}
timer.cancel(); // 取消所有任務,執行緒結束
task.cancel(); // 取消單一任務
timer.purge(); // 從佇列移除已取消任務,釋放記憶體
| 方案 | 適用場景 | 優點 |
|---|---|---|
| ScheduledExecutorService | 高併發、需多執行緒排程 | 執行緒池、彈性配置、異常隔離 |
| Spring @Scheduled | Spring 生態專案 | 聲明式、支援 Cron、整合事務 |
| Quartz | 複雜排程、叢集、持久化 | 功能豐富、企業級可靠度 |
Timer/TimerTask 適合簡單、輕量、單機的定時需求。理解 schedule 與 scheduleAtFixedRate 的語義差異對正確實現業務邏輯至關重要。生產環境建議遷移至 ScheduledExecutorService 或 Spring 排程框架以獲得更好穩定性與擴展性。