Java 標準庫 java.util.Timer 與 TimerTask 雖能處理簡單延遲/固定頻率任務,但無法應對「每天固定時間執行」(夏令時跳變)、複雜日曆規則(工作日/週末不同時刻)、天文計算(日出日落)等真實業務場景。本文構建一個基於 ScheduleIterator 迭代器模式的通用調度框架,將調度策略與執行機制解耦,靈活支持任意複雜的重復任務計劃。
定義極簡接口,將調度語義封裝為時間序列生成器:
public interface ScheduleIterator { Date next(); // 返回下一次執行時間,null 表示取消 }框架內部將每次
next()返回的時間點作為單次Timer任務觸發點,執行完畢自動請求下一個時間點,形成鏈式調度。內置迭代器實現
DailyIterator:每日固定時間(自動處理夏令時)
利用
Calendar運算,構造函數接收hour, minute, second,next()每次加一天。GregorianCalendar內建夏令時規則,無需手動處理時鐘跳變。RestrictedDailyIterator:指定星期幾執行
繼承每日邏輯,增加
allowedDaysOfWeek數組過濾,next()循環前進直到命中允許日期。CompositeIterator:組合多個迭代器
接收
ScheduleIterator[],內部維護優先隊列合併多個時間序列,輸出全局有序時間流。例如:「工作日 08:00,週末 09:00」僅需組合兩個RestrictedDailyIterator,無需編寫雙 crontab 條目。調度器核心實現
SchedulerTask:可取消、狀態感知的任務包裝
繼承
Runnable,維護VIRGIN/SCHEDULED/CANCELLED三態,線程安全地支持cancel()、scheduledExecutionTime()。Scheduler:單 Timer 多任務串聯
單例
Timer實例,schedule(task, iterator)啟動首次執行,內部SchedulerTimerTask.run()執行業務邏輯後調用reschedule()獲取下一時間點繼續鏈接。狀態機確保不重複調度、取消後不再執行。實時性保證與延遲分析
Timer 使用 Object.wait(),框架二次等待確保不早於計劃時間System.currentTimeMillis() - scheduledExecutionTime(),構建延遲分佈統計,超閾值可選擇放棄執行-Xincgc)引入 Calendrical Calculations 庫計算指定經緯度日落時間,實現「日落前 15 分鐘開燈」—— 這類非固定周期規則 cron 完全無法表達,而 ScheduleIterator 輕鬆封裝。
| 特性 | Timer/TimerTask | 本框架 |
|---|---|---|
| 每日固定時間 | 需手動處理夏令時 | DailyIterator 自動處理 |
| 複雜日曆規則 | 不支持 | 組合迭代器任意表達 |
| 非週期規則(天文/業務) | 無法表達 | 自定義 Iterator 實現 |
| 調度策略可測試性 | 困難 | Iterator 可獨立單元測試 |
這個不到 200 行的框架,以「迭代器即調度」的極簡抽象,賦予 Java 應用表達任意時間語義的能力,是定時任務領域的「最小可行內核」。