Davids原理探究:ScheduledThreadPoolExecutor原理

ScheduledThreadPoolExecutor原理

關注可以查看更多粉絲專享blog~

ScheduledThreadPoolExecutor狀態

內部變量period

  1. period == 0,則爲一次性任務。
  2. period < 0,則爲fixed-delay,固定延時的定時可重複執行任務。
  3. 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方法
ScheduledFutureTask類圖

週期性任務

任務會一直運行直到任務中拋出異常/被取消/關閉線程池

  1. scheduleWithFixedDelay,固定延時的定時可重複執行任務,上一個任務執行完之後 + period = 下一次執行的時間。
  2. 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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章