推薦配置速查
// 定時調度器:2 核心線程
private static final ScheduledThreadPoolExecutor SCHEDULER =
new ScheduledThreadPoolExecutor(2);
// 業務線程池:10 核心線程
private static final ExecutorService EXECUTOR =
Executors.newFixedThreadPool(10);
// 使用示例
SCHEDULER.scheduleAtFixedRate(new Task(), 5, 180, TimeUnit.SECONDS); // 5s 後每 3 分鐘執行
EXECUTOR.execute(new Task());
Task 實現範例
class Task implements Runnable {
@Override public void run() { System.out.println("執行任務..."); }
}
Timer vs ScheduledThreadPoolExecutor 深度對比
| 維度 | Timer | ScheduledThreadPoolExecutor |
| 時間基準 | 絕對時間(敏感於系統時間修改) | 相對時間(不受系統時間影響) |
| 線程模型 | 單線程串行執行所有任務 | 線程池並發執行,可配置核心數 |
| 異常處理 | 任務拋出未檢查異常 → Timer 線程終止 → 所有後續任務停止 | 單任務異常被捕獲隔離,不影響其他任務 |
| 取消/管理 | 僅 cancel() 整個 Timer | 支持 Future.cancel() 單任務取消,shutdown() 整體關閉 |
| API 豐富度 | 簡單 | 支持固定延遲、固定頻率、自定義 Trigger、可查詢隊列狀態 |
異常隔離實戰驗證
ScheduledThreadPoolExecutor scheduler = new ScheduledThreadPoolExecutor(2);
scheduler.scheduleAtFixedRate(() -> { throw new RuntimeException("任務1崩潰"); }, 2, 5, TimeUnit.SECONDS);
scheduler.scheduleAtFixedRate(() -> System.out.println("任務2正常"), 2, 5, TimeUnit.SECONDS);
// 結果:任務1反覆拋異常,任務2不受影響持續輸出
最佳實踐建議
- 棄用 Timer:新代碼統一使用
ScheduledThreadPoolExecutor 或 Spring @Scheduled(底層同樣基於它)。
- 分離調度與執行:調度器僅負責觸發,耗時業務提交至業務線程池(
EXECUTOR.submit(() -> scheduler.execute(task))),避免長任務佔用調度線程導致後續調度延遲。
- 優雅關閉:應用停止時調用
scheduler.shutdown()、executor.shutdown(),配合 awaitTermination 等待任務完成。
- 監控指標:暴露隊列積壓數、活躍線程數、任務執行耗時(Micrometer/Prometheus)。
Spring Boot 整合示例
@Configuration
@EnableScheduling
public class SchedulerConfig {
@Bean public TaskScheduler taskScheduler() {
ThreadPoolTaskScheduler s = new ThreadPoolTaskScheduler();
s.setPoolSize(2);
s.setThreadNamePrefix("scheduler-");
return s;
}
@Bean public ExecutorService executorService() {
return Executors.newFixedThreadPool(10);
}
}