java.util.Timer + TimerTask 是 JDK 內建的輕量級排程器,適合單機、簡單、非分散式的週期性任務(如每 5 分鐘抓取一次 API、每天凌晨備份資料)。若需分散式、高可用、彈性排程,請改用 Quartz、Spring @Scheduled 或 XXL-JOB。
Runnable 的抽象類,覆寫 run() 放入業務邏輯。schedule(task, delay):一次性延遲執行schedule(task, delay, period):固定延遲週期(上次結束 → 等 period → 下次開始)scheduleAtFixedRate(task, delay, period):固定頻率週期(上次開始 → 等 period → 下次開始)import java.io.*;
import java.net.*;
import java.util.*;
import com.fasterxml.jackson.databind.*;
public class NetworkDataFetcher {
private static final String API_URL = "https://api.example.com/data";
private static final ObjectMapper MAPPER = new ObjectMapper();
private static final Timer TIMER = new Timer(true); // 守護執行緒,JVM 退出自動結束
public static void main(String[] args) {
TimerTask task = new TimerTask() {
@Override public void run() {
try {
fetchAndProcess();
} catch (Exception e) {
logError("任務執行異常", e);
}
}
};
// 啟動:立即執行一次,之後每 30 秒固定頻率
TIMER.scheduleAtFixedRate(task, 0, 30_000);
Runtime.getRuntime().addShutdownHook(new Thread(TIMER::cancel));
}
private static void fetchAndProcess() throws IOException {
URL url = new URL(API_URL);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
conn.setReadTimeout(10000);
conn.setRequestProperty("Accept", "application/json");
try (InputStream is = conn.getInputStream()) {
JsonNode root = MAPPER.readTree(is);
// 業務處理:例如提取特定欄位、存入資料庫、發送通知
String value = root.path("data").path("value").asText();
System.out.printf("[%s] 獲取成功: %s%n", new Date(), value);
} finally {
conn.disconnect();
}
}
private static void logError(String msg, Exception e) {
System.err.printf("[%s] %s: %s%n", new Date(), msg, e.getMessage());
}
}
| 場景 | 建議 | 理由 |
|---|---|---|
| 任務耗時 > 週期 | 改用 ScheduledExecutorService 多執行緒 | Timer 單執行緒,前一任務阻塞會延遲後續任務 |
| 需彈性停止/暫停 | 保存 TimerTask 參考,呼叫 cancel() | Timer.cancel() 會清空所有任務,粒度太粗 |
| 異常處理 | run() 內部 try-catch,記錄日誌不拋出 | 未捕獲異常會導致 Timer 執行緒死亡,所有任務停止 |
| 資料庫/HTTP 連線 | 使用連線池,設定連線/讀取超時 | 避免長時間阻塞排程執行緒 |
| JVM 關閉 | 註冊 ShutdownHook 呼叫 timer.cancel() | 確保資源釋放、非守護執行緒正常結束 |
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(r -> {
Thread t = new Thread(r, "DataFetcher");
t.setDaemon(true); return t;
});
scheduler.scheduleAtFixedRate(() -> {
try { fetchAndProcess(); }
catch (Exception e) { logError("任務異常", e); }
}, 0, 30, TimeUnit.SECONDS);
// 關閉:scheduler.shutdown();
Future 取消單一任務。@Scheduled(fixedRate = 30000) + @EnableScheduling 更簡潔。TimerTask 是輕量級定時任務的入門選擇,但單執行緒、異常脆弱、無持久化限制了其生產適用性。理解其運作機制與避坑指南,能在小型專案、原型驗證、維護腳本中快速落地;正式系統建議遷移至 ScheduledExecutorService 或成熟排程框架。