java.util.Timer 與 TimerTask 是 JDK 內建的輕量級排程工具,適合簡單的單機定時需求。本文示範三種最常見的排程模式。
package com.example.timer;
import java.awt.Desktop;
import java.io.*;
import java.net.URI;
import java.nio.charset.Charset;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Timer;
import java.util.TimerTask;
public class TimerTaskDemo {
public static void main(String[] args) throws ParseException {
Timer timer = new Timer();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// 1. 延遲 1 秒執行一次
timer.schedule(new TimerTask() {
@Override public void run() {
System.out.println("⏱ 時間流逝 1 秒!");
}
}, 1000); // delay ms
// 2. 指定絕對時間執行一次
timer.schedule(new TimerTask() {
@Override public void run() {
try {
Desktop.getDesktop().browse(new URI("https://www.baidu.com"));
} catch (Exception e) {
e.printStackTrace();
}
}
}, sdf.parse("2025-12-31 23:59:59")); // 指定 Date
// 3. 延遲 10 秒啟動,之後每 5 秒執行一次(固定頻率)
timer.schedule(new TimerTask() {
@Override public void run() {
try {
Process p = Runtime.getRuntime().exec("ping www.baidu.com");
try (BufferedInputStream in = new BufferedInputStream(p.getInputStream());
BufferedReader br = new BufferedReader(new InputStreamReader(in, Charset.forName("GBK")))) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
}
if (p.waitFor() != 0) {
System.err.println("指令執行失敗,exit code: " + p.exitValue());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}, 10_000, 5_000); // delay, period
// 程式不會自動結束,需手動停止(或加 timer.cancel() 條件)
}
}
schedule 簽名差異| 方法 | 參數 | 行為 | 適用場景 |
|---|---|---|---|
schedule(task, delay) | delay (ms) | 延遲 delay 後執行一次 | 啟動延遲初始化、一次性提醒 |
schedule(task, time) | Date | 在指定時刻執行一次 | 定點備份、定時發報 |
schedule(task, delay, period) | delay, period (ms) | 延遲 delay 後,每 period 執行一次(固定頻率,不補償) | 心跳、輪詢、定期清理 |
scheduleAtFixedRate(task, delay, period) | delay, period (ms) | 延遲 delay 後,每 period 執行一次(固定速率,會補償) | 精準週期、動畫幀率 |
關鍵差異:schedule(固定頻率)若上次執行超時,下一次會在「上次結束 + period」啟動;scheduleAtFixedRate(固定速率)會嘗試在「首次啟動 + N×period」啟動,若超時會連續執行追趕進度。
Timer 內部只有一個背景執行緒,任務執行時間過長會阻塞後續任務。耗時任務請用 ScheduledExecutorService。TimerTask.run() 拋出未捕獲異常會導致整個 Timer 執行緒死亡,後續所有任務停止。務必在 run() 內 try-catch 並記錄日誌。timer.cancel(),並處理 TimerTask 內的 I/O 資源釋放。Timer 精度約 10-15ms,毫秒級嚴格週期請用 ScheduledExecutorService 或 Quartz。Date 時注意時區,建議改用 Instant / ZonedDateTime + ScheduledExecutorService。Runnable/Callable、可取消單一任務、異常隔離。