ScheduledThreadPoolExecutor原理
關注可以查看更多粉絲專享blog~
內部變量period
- period == 0,則爲一次性任務。
- period < 0,則爲fixed-delay,固定延時的定時可重複執行任務。
- period > 0,則爲fixed-rate,固定頻率的定時可重複執行任務。
一次性任務
public ScheduledFuture<?> schedule(Runnable command,
long delay,
TimeUnit unit) {
// 參數校驗
if (command == null || unit == null)
throw new NullPointerException();
// 構造任務
RunnableScheduledFuture<?> t = decorateTask(command,
new ScheduledFutureTask<Void>(command, null,
triggerTime(delay, unit)));
// 添加任務到延時隊列,
delayedExecute(t);
return t;
}
private void delayedExecute(RunnableScheduledFuture<?> task) {
// 狀態爲shutdown則執行拒絕策略
if (isShutdown())
reject(task);
else {
// 添加任務到延時隊列
super.getQueue().add(task);
// 再次判斷狀態,期間可能有其他線程執行了shutdown操作,如果是shutdown則中斷任務並移出隊列
if (isShutdown() &&
!canRunInCurrentRunState(task.isPeriodic()) &&
remove(task))
task.cancel(false);
else
ensurePrestart();
}
}
// 確保至少一個線程在處理任務
// 1、如果工作線程數小於核心線程數則增加核心線程數
// 2、如果工作線程數 == 0,則啓動一個線程
void ensurePrestart() {
int wc = workerCountOf(ctl.get());
if (wc < corePoolSize)
addWorker(null, true);
else if (wc == 0)
addWorker(null, false);
}
ScheduledFutureTask重寫了 DelayQueue 的getDelay和compareTo方法
週期性任務
任務會一直運行直到任務中拋出異常/被取消/關閉線程池。
- scheduleWithFixedDelay,固定延時的定時可重複執行任務,上一個任務執行完之後 + period = 下一次執行的時間。
- scheduleWithFixedRate,固定頻率的定時可重複任務,上一個任務無論有沒有執行完下一次任務都會以initdelday + n * period啓動任務,但是 不會併發執行,知道當前任務執行完畢之後再執行。
run()方法
public void run() {
// 是否爲週期性任務 isPeriodic(): return period != 0;
boolean periodic = isPeriodic();
// 不是則檢查是否可以取消
if (!canRunInCurrentRunState(periodic))
cancel(false);
// 非週期性任務執行run方法,super is FutureTask
else if (!periodic)
ScheduledFutureTask.super.run();
// 週期性任務執行runAndReset(),super is FutureTask
else if (ScheduledFutureTask.super.runAndReset()) {
// 設置下一次運行時間
setNextRunTime();
// 重新執行當前任務(入隊DelayQueue)
reExecutePeriodic(outerTask);
}
}
// 是否可以取消executeExistingDelayedTasksAfterShutdown默認爲true,如果調用shutdown之後可繼續執行
boolean canRunInCurrentRunState(boolean periodic) {
return isRunningOrShutdown(periodic ?
continueExistingPeriodicTasksAfterShutdown :
executeExistingDelayedTasksAfterShutdown);
}
// 一次性任務ScheduledFutureTask.super.run();
public void run() {
// 狀態不爲NEW或者執行線程不是當前線程則return
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
// 再次判斷是否爲NEW,可能被中斷(能夠執行到此處的只有一個線程,因爲CAS只有一個線程可以設置成功)
if (c != null && state == NEW) {
V result;
boolean ran;
try {
// 執行任務
result = c.call();
ran = true;
} catch (Throwable ex) {
// 出現異常則設置狀態爲EXCEPTION
result = null;
ran = false;
setException(ex);
}
// 成功則設置結果
if (ran)
set(result);
}
} finally {
// 運行器必須爲非null,直到狀態穩定下來,防止併發調用run()
runner = null;
// 必須在將運行器歸零之後重新讀取狀態,以防止泄漏中斷
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
// 週期性任務ScheduledFutureTask.super.runAndReset();
protected boolean runAndReset() {
// 狀態不爲NEW或者執行線程不是當前線程則return
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return false;
boolean ran = false;
int s = state;
try {
Callable<V> c = callable;
// 再次判斷是否爲NEW,可能被中斷(能夠執行到此處的只有一個線程,因爲CAS只有一個線程可以設置成功)
if (c != null && s == NEW) {
try {
// 執行任務,不設置結果
c.call();
ran = true;
} catch (Throwable ex) {
setException(ex);
}
}
} finally {
// 運行器必須爲非null,直到狀態穩定下來,防止併發調用run()
runner = null;
// 必須在將運行器歸零之後重新讀取狀態,以防止泄漏中斷
s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
// 返回執行結果如果成功則設置任務狀態爲NEW
return ran && s == NEW;
}