ScheduledThreadPoolExecutor 繼承 ThreadPoolExecutor,新增兩大關鍵內部類:
private final long sequenceNumber; // 入隊順序,保證 FIFO
private long time; // 下次執行時間 (nanoTime)
private final long period; // >0 固定頻率,<0 固定延遲,=0 單次
private int heapIndex; // 堆中索引,支援 O(1) 移除/更新
public long getDelay(TimeUnit unit) {
return unit.convert(time - now(), NANOSECONDS);
}
返回任務距離執行還需等待的時間,供隊列排序與 take() 阻塞使用。
public int compareTo(Delayed other) {
if (other == this) return 0;
if (other instanceof ScheduledFutureTask) {
ScheduledFutureTask> x = (ScheduledFutureTask>) other;
long diff = time - x.time;
if (diff < 0) return -1;
if (diff > 0) return 1;
return sequenceNumber < x.sequenceNumber ? -1 : 1; // 時間同則按入隊序
}
long d = getDelay(NANOSECONDS) - other.getDelay(NANOSECONDS);
return (d < 0) ? -1 : (d > 0) ? 1 : 0;
}
最小堆比較器:優先按 time,次按 sequenceNumber 保證穩定性。
private void setNextRunTime() {
long p = period;
if (p > 0) time += p; // 固定頻率:上次執行時間 + 週期
else time = triggerTime(-p); // 固定延遲:當前時間 + 延遲
}
long triggerTime(long delay) {
return now() + ((delay < (Long.MAX_VALUE >> 1)) ? delay : overflowFree(delay));
}
private long overflowFree(long delay) {
Delayed head = (Delayed) super.getQueue().peek();
if (head != null) {
long headDelay = head.getDelay(NANOSECONDS);
if (headDelay < 0 && delay - headDelay < 0) return Long.MAX_VALUE + headDelay;
}
return delay;
}
防止 compareTo 中相減溢出:若隊列頭任務已過期(負延遲),新任務延遲不得導致計算溢出。
| 模式 | 方法 | period 符號 | 下次執行時間計算 | 適用場景 |
|---|---|---|---|---|
| 固定頻率 | scheduleAtFixedRate | 正數 | 上次執行時間 + period | 心跳、定時掃描 |
| 固定延遲 | scheduleWithFixedDelay | 負數 | 上次執行結束時間 + |period| | 任務耗時不定、需間隔 |
RunnableScheduledFuture[] queue,初始容量 16,動態擴容。heapIndex 讓 remove() 達到 O(log n) 而非 O(n) 掃描。take() 若堆頂任務未到期,精確 LockSupport.parkNanos(delay) 休眠,避免忙等待。drainTo() 支援批量導出,配合 shutdownNow() 快速清空。ScheduledThreadPoolExecutor 通過最小堆延遲隊列 + 時間戳驅動 + 週期重算,實現了高效、精準的定時調度。理解 ScheduledFutureTask 的 time/period/sequenceNumber 交互,是掌握其核心的鑰匙。