ScheduledThreadPoolExecutor源碼

普通的線程池執行流程,應該很多人都知道了,可是定時任務線程更爲重要,很多框架都用到了,應用場景有很多,比如心跳,拉取信息,redisson鎖的續約,同步數據等

public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
}
//shutdown後是否繼續執行定時任務
 private volatile boolean continueExistingPeriodicTasksAfterShutdown;

 //shutdown後是否繼續執行延遲任務
 private volatile boolean executeExistingDelayedTasksAfterShutdown = true;

//cancle方法收費需要將該任務從隊列移除
 private volatile boolean removeOnCancel = false;

 //任務的序列號
 private static final AtomicLong sequencer = new AtomicLong();
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
                                                  long initialDelay,
                                                  long period,
                                                  TimeUnit unit) {
        if (command == null || unit == null)
            throw new NullPointerException();
        if (period <= 0)
            throw new IllegalArgumentException();
        ScheduledFutureTask<Void> sft =
            new ScheduledFutureTask<Void>(command,
                                          null,
                                          triggerTime(initialDelay, unit),
                                          unit.toNanos(period));
        RunnableScheduledFuture<Void> t = decorateTask(command, sft);
        sft.outerTask = t;
        delayedExecute(t);
        return t;
 }
ScheduledFutureTask
public void run() {
            //判斷任務是否週期執行
            boolean periodic = isPeriodic();
            //檢查當前狀態能否執行任務
            if (!canRunInCurrentRunState(periodic))
                cancel(false);
            //非週期任務直接執行,只執行一次
            else if (!periodic)
                ScheduledFutureTask.super.run();
            //週期任務的執行
            else if (ScheduledFutureTask.super.runAndReset()) {
                //設置下一次執行任務時間
                setNextRunTime();
                //任務的下一次執行
                reExecutePeriodic(outerTask);
            }
}
//沒做什麼事情,留給後面的擴展點
protected <V> RunnableScheduledFuture<V> decorateTask(
        Runnable runnable, RunnableScheduledFuture<V> task) {
        return task;
}
private void delayedExecute(RunnableScheduledFuture<?> task) {
        //校驗線程池狀態,如果已經停止,則拒絕
        if (isShutdown())
            reject(task);
        else {
            //加入隊列
            super.getQueue().add(task);
            //再次檢查,線程池狀態發生變化,不能夠執行,移出隊列,取消任務
            if (isShutdown() &&
                !canRunInCurrentRunState(task.isPeriodic()) &&
                remove(task))
                task.cancel(false);
            else
                //開啓線程
                ensurePrestart();
        }
    }
DelayedWorkQueue,阻塞獲取頭結點
public RunnableScheduledFuture<?> take() throws InterruptedException {
            final ReentrantLock lock = this.lock;
            lock.lockInterruptibly();
            try {
                for (;;) {
                    RunnableScheduledFuture<?> first = queue[0];
                    if (first == null)
                        available.await();
                    else {
                        long delay = first.getDelay(NANOSECONDS);
                        if (delay <= 0)
                            return finishPoll(first);
                        first = null; // don't retain ref while waiting
                        if (leader != null)
                            //已經存在leader線程,當前線程await阻塞
                            available.await();
                        else {
                            //當前線程作爲leader線程,並制定頭結點的延遲時間作爲阻塞時間
                            Thread thisThread = Thread.currentThread();
                            leader = thisThread;
                            try {
                                available.awaitNanos(delay);
                            } finally {
                                if (leader == thisThread)
                                    leader = null;
                            }
                        }
                    }
                }
            } finally {
                //leader線程沒有阻塞,可以找到頭結點,喚醒阻塞線程
                if (leader == null && queue[0] != null)
                    available.signal();
                lock.unlock();
            }
        }
//根據前面設置的時間,跟當前時間比較,計算要等待的時間 
public long getDelay(TimeUnit unit) {
            return unit.convert(time - now(), NANOSECONDS);
        }

 

//進行按時間排序,形成一個小頂堆
private void siftUp(int k, RunnableScheduledFuture<?> key) {
            while (k > 0) {
                int parent = (k - 1) >>> 1;
                RunnableScheduledFuture<?> e = queue[parent];
                if (key.compareTo(e) >= 0)
                    break;
                queue[k] = e;
                setIndex(e, k);
                k = parent;
            }
            queue[k] = key;
            setIndex(key, k);
        }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章