ScheduledThreadPoolExecutor原理分析

線程池就是維持幾個(gè)工作線程,然后從任務(wù)隊(duì)列中獲取任務(wù)執(zhí)行。所以要實(shí)現(xiàn)延時(shí)或者定時(shí)執(zhí)行任務(wù),就要做到以下三點(diǎn):

  1. 任務(wù)要能返回它的延時(shí)時(shí)間和是否為定時(shí)任務(wù)。
  2. 任務(wù)隊(duì)列要根據(jù)任務(wù)的延時(shí)時(shí)間進(jìn)行排序。這個(gè)我們在上一章DelayedWorkQueue原理分析中已經(jīng)講解過了。
  3. 如果是定時(shí)任務(wù),任務(wù)執(zhí)行完成之后,還可以再次執(zhí)行它。

所以要分析ScheduledThreadPoolExecutor原理關(guān)鍵就是對它的任務(wù)類ScheduledFutureTask的分析。

    private class ScheduledFutureTask<V>
            extends FutureTask<V> implements RunnableScheduledFuture<V> {}

FutureTask類我們已經(jīng)在以前的文章分析過了,而RunnableScheduledFuture接口的作用是什么呢?

一. RunnableScheduledFuture接口

我們知道要實(shí)現(xiàn)延時(shí)或者定時(shí)執(zhí)行任務(wù),任務(wù)要能返回它的延時(shí)時(shí)間,任務(wù)是否為定時(shí)任務(wù),任務(wù)能根據(jù)延時(shí)時(shí)間排序。所以可以想象出RunnableScheduledFuture接口中的方法了。

public interface Comparable<T> {
    // 比較兩個(gè)實(shí)例的大小
    public int compareTo(T o);
}
/**
 * 實(shí)現(xiàn)Comparable接口,說明Delayed實(shí)例可以進(jìn)行比較
 */
public interface Delayed extends Comparable<Delayed> {

    /**
     * @return 返回剩余的延時(shí)時(shí)間
     */
    long getDelay(TimeUnit unit);
}

/**
 * 實(shí)現(xiàn)了Delayed接口,可以返回延時(shí)時(shí)間以及能夠根據(jù)延時(shí)時(shí)間進(jìn)行比較
 */
public interface ScheduledFuture<V> extends Delayed, Future<V> {
}

// 繼承自Runnable和Future接口??梢援?dāng)做Runnable實(shí)例使用
public interface RunnableFuture<V> extends Runnable, Future<V> {
    // 運(yùn)行任務(wù)
    void run();
}

public interface RunnableScheduledFuture<V> extends 
                 RunnableFuture<V>, ScheduledFuture<V> {

    /**
     * 是否為周期定時(shí)任務(wù)
     * @return 返回true,表示是定時(shí)任務(wù)
     */
    boolean isPeriodic();
}

RunnableScheduledFuture接口中,最重要的就是這四個(gè)方法:

  1. compareTo(T o): 可以比較任務(wù)的延時(shí)時(shí)間,進(jìn)行排序用的。
  2. getDelay(TimeUnit unit): 返回任務(wù)剩余的延時(shí)時(shí)間
  3. run(): 運(yùn)行任務(wù)。如果是定時(shí)任務(wù),任務(wù)完成之后,還可以繼續(xù)執(zhí)行。
  4. isPeriodic(): 是否為周期定時(shí)任務(wù)

二. 何時(shí)創(chuàng)建ScheduledFutureTask任務(wù)

何時(shí)創(chuàng)建ScheduledFutureTask任務(wù),就是ScheduledExecutorService接口四個(gè)方法會創(chuàng)建ScheduledFutureTask任務(wù)實(shí)例。

2.1 創(chuàng)建延時(shí)任務(wù)

    // 給定的延遲時(shí)間delay之后,才會執(zhí)行任務(wù)command
    public ScheduledFuture<?> schedule(Runnable command,
                                       long delay,
                                       TimeUnit unit) {
        if (command == null || unit == null)
            throw new NullPointerException();
        /**
         * 創(chuàng)建一個(gè)延時(shí)任務(wù)ScheduledFutureTask實(shí)例。
         * triggerTime方法會根據(jù)給定的延時(shí)時(shí)間delay,返回任務(wù)開始的時(shí)間。
         * decorateTask方法是讓子類能夠修飾ScheduledFutureTask任務(wù)實(shí)例,本類中沒做處理。
         */
        RunnableScheduledFuture<?> t = decorateTask(command,
            new ScheduledFutureTask<Void>(command, null,
                                          triggerTime(delay, unit)));
        // 延時(shí)執(zhí)行任務(wù)
        delayedExecute(t);
        return t;
    }

    // 給定的延遲時(shí)間delay之后,才會執(zhí)行任務(wù)callable
    public <V> ScheduledFuture<V> schedule(Callable<V> callable,
                                           long delay,
                                           TimeUnit unit) {
        if (callable == null || unit == null)
            throw new NullPointerException();
        /**
         * 創(chuàng)建一個(gè)延時(shí)任務(wù)ScheduledFutureTask實(shí)例。
         * triggerTime方法會根據(jù)給定的延時(shí)時(shí)間delay,返回任務(wù)開始的時(shí)間。
         * decorateTask方法是讓子類能夠修飾ScheduledFutureTask任務(wù)實(shí)例,本類中沒做處理。
         */
        RunnableScheduledFuture<V> t = decorateTask(callable,
            new ScheduledFutureTask<V>(callable,
                                       triggerTime(delay, unit)));
        // 延時(shí)執(zhí)行任務(wù)
        delayedExecute(t);
        return t;
    }

這兩個(gè)方法的流程是一樣的,只不過一個(gè)是Runnable類型的任務(wù),一個(gè)Callable類型的任務(wù)。

  1. 調(diào)用triggerTime方法根據(jù)給定的延時(shí)時(shí)間delay,返回任務(wù)開始的時(shí)間。
  2. 創(chuàng)建一個(gè)延時(shí)任務(wù)ScheduledFutureTask實(shí)例。
  3. 調(diào)用decorateTask方法是讓子類能夠修飾ScheduledFutureTask任務(wù)實(shí)例。
  4. 調(diào)用delayedExecute(t)方法延時(shí)執(zhí)行任務(wù)。

2.2 創(chuàng)建延時(shí)定時(shí)任務(wù)

    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();
        /**
         * 創(chuàng)建一個(gè)延時(shí)定時(shí)任務(wù)ScheduledFutureTask實(shí)例。
         * triggerTime方法會根據(jù)給定的延時(shí)時(shí)間delay,返回任務(wù)開始的時(shí)間。
         */
        ScheduledFutureTask<Void> sft =
            new ScheduledFutureTask<Void>(command,
                                          null,
                                          triggerTime(initialDelay, unit),
                                          unit.toNanos(period));
        // decorateTask方法是讓子類能夠修飾ScheduledFutureTask任務(wù)實(shí)例,本類中沒做處理。
        RunnableScheduledFuture<Void> t = decorateTask(command, sft);
        // outerTask作用就是下一次定時(shí)執(zhí)行的任務(wù),在reExecutePeriodic方法中需要
        sft.outerTask = t;
        // 延時(shí)執(zhí)行任務(wù)
        delayedExecute(t);
        return t;
    }

    public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
                                                     long initialDelay,
                                                     long delay,
                                                     TimeUnit unit) {
        if (command == null || unit == null)
            throw new NullPointerException();
        if (delay <= 0)
            throw new IllegalArgumentException();
        /**
         * 創(chuàng)建一個(gè)延時(shí)定時(shí)任務(wù)ScheduledFutureTask實(shí)例。
         * triggerTime方法會根據(jù)給定的延時(shí)時(shí)間delay,返回任務(wù)開始的時(shí)間。
         */
        ScheduledFutureTask<Void> sft =
            new ScheduledFutureTask<Void>(command,
                                          null,
                                          triggerTime(initialDelay, unit),
                                          unit.toNanos(-delay));
        // decorateTask方法是讓子類能夠修飾ScheduledFutureTask任務(wù)實(shí)例,本類中沒做處理。
        RunnableScheduledFuture<Void> t = decorateTask(command, sft);
        // outerTask作用就是下一次定時(shí)執(zhí)行的任務(wù),在reExecutePeriodic方法中需要
        sft.outerTask = t;
        // 延時(shí)執(zhí)行任務(wù)
        delayedExecute(t);
        return t;
    }

我們知道scheduleAtFixedRate方法是固定周期時(shí)間去執(zhí)行任務(wù),而scheduleWithFixedDelay方法是在任務(wù)完成之后,延時(shí)delay時(shí)間再去執(zhí)行任務(wù)。
但是我們發(fā)現(xiàn)這兩個(gè)方法幾乎是一模一樣的,唯一不同地就是創(chuàng)建延時(shí)定時(shí)任務(wù)ScheduledFutureTask實(shí)例時(shí),一個(gè)傳遞的是正數(shù)period,一個(gè)傳遞的是負(fù)數(shù)-delay。

  1. 調(diào)用triggerTime方法根據(jù)給定的延時(shí)時(shí)間delay,返回任務(wù)開始的時(shí)間。
  2. 創(chuàng)建一個(gè)延時(shí)定時(shí)任務(wù)ScheduledFutureTask實(shí)例。
  3. 調(diào)用decorateTask方法是讓子類能夠修飾ScheduledFutureTask任務(wù)實(shí)例。
  4. 設(shè)置outerTask,作用就是下一次定時(shí)執(zhí)行的任務(wù),在reExecutePeriodic方法中需要。
  5. 延時(shí)執(zhí)行任務(wù)。

2.3 triggerTime方法

    /**
     * 返回延時(shí)任務(wù)開始的時(shí)間
     */
    private long triggerTime(long delay, TimeUnit unit) {
        return triggerTime(unit.toNanos((delay < 0) ? 0 : delay));
    }

    /**
     * 返回延時(shí)任務(wù)開始的時(shí)間。利用當(dāng)前時(shí)間加上給定的延時(shí)時(shí)間
     */
    long triggerTime(long delay) {
        return now() +
            ((delay < (Long.MAX_VALUE >> 1)) ? delay : overflowFree(delay));
    }

2.4 decorateTask方法

    /**
     * 讓子類能夠修飾或者替換任務(wù)task。
     * 這里只是簡單地返回task
     */
    protected <V> RunnableScheduledFuture<V> decorateTask(
        Runnable runnable, RunnableScheduledFuture<V> task) {
        return task;
    }

2.5 delayedExecute方法

    private void delayedExecute(RunnableScheduledFuture<?> task) {
        // 如果線程池不是RUNNING狀態(tài),那么調(diào)用reject(task)方法,
        // 拒絕執(zhí)行任務(wù)task
        if (isShutdown())
            reject(task);
        else {
            // 將任務(wù)添加到任務(wù)隊(duì)列中,會根據(jù)任務(wù)的延時(shí)時(shí)間進(jìn)行排序
            super.getQueue().add(task);
            /**
             * 如果線程池不是RUNNING狀態(tài),那么就判斷能不能在當(dāng)前狀態(tài)下運(yùn)行,
             * 主要就是能不能在SHUTDOWN狀態(tài)下運(yùn)行。
             * 如果不能在當(dāng)前狀態(tài)下運(yùn)行,那么就調(diào)用remove方法,
             * 從任務(wù)隊(duì)列中移除剛剛添加的任務(wù)task。
             *
             * 只有移除成功了,才可以調(diào)用task.cancel(false)方法取消任務(wù),
             * 否則這個(gè)延時(shí)任務(wù)task都還要執(zhí)行。
             */
            if (isShutdown() &&
                !canRunInCurrentRunState(task.isPeriodic()) &&
                remove(task))
                task.cancel(false);
            else
                // 預(yù)先啟動(dòng)工作線程,確保線程池中有工作線程。
                ensurePrestart();
        }
    }

這個(gè)方法的主要作用就是將任務(wù)添加到任務(wù)隊(duì)列中,因?yàn)檫@里任務(wù)隊(duì)列是優(yōu)先級隊(duì)列DelayedWorkQueue,它會根據(jù)任務(wù)的延時(shí)時(shí)間進(jìn)行排序。

  1. 如果線程池不是RUNNING狀態(tài),不能執(zhí)行延時(shí)任務(wù)task,那么調(diào)用reject(task)方法,拒絕執(zhí)行任務(wù)task。
  2. 將任務(wù)添加到任務(wù)隊(duì)列中,會根據(jù)任務(wù)的延時(shí)時(shí)間進(jìn)行排序。
  3. 因?yàn)槭嵌嗑€程并發(fā)環(huán)境,就必須判斷在添加任務(wù)的過程中,線程池狀態(tài)是否被別的線程更改了,那么就可能要取消任務(wù)了。
  4. 將任務(wù)添加到任務(wù)隊(duì)列后,還要確保線程池中有工作線程,不然任務(wù)也不為執(zhí)行。所以ensurePrestart()方法預(yù)先啟動(dòng)工作線程,確保線程池中有工作線程。

與ThreadPoolExecutor類中execute方法執(zhí)行任務(wù)方法不同:

  1. 因?yàn)槭茄訒r(shí)任務(wù)task,所以不能將任務(wù)當(dāng)成工作線程第一個(gè)任務(wù),只能將任務(wù)添加到任務(wù)隊(duì)列中,等待著工作線程來執(zhí)行。
  2. 任務(wù)隊(duì)列DelayedWorkQueue容量幾乎是無限的,所以也不需要最大池。除非核心池?cái)?shù)量是0,那么必須創(chuàng)建一個(gè)工作線程來運(yùn)行任務(wù),否則線程池的線程數(shù)不可能超過核心池?cái)?shù)量。
  3. 當(dāng)線程池狀態(tài)被別的線程改變時(shí),取消任務(wù)的判斷條件不同。當(dāng)線程池狀態(tài)不是RUNNING,而且不能在當(dāng)前狀態(tài)下運(yùn)行,那么就調(diào)用remove方法,移除剛剛添加的任務(wù)task。只有移除任務(wù)成功,才可以調(diào)用task.cancel(false)方法取消任務(wù),否則這個(gè)延時(shí)任務(wù)task都還要執(zhí)行。

2.6 canRunInCurrentRunState方法

    // 判斷能不能在當(dāng)前狀態(tài)下運(yùn)行
    boolean canRunInCurrentRunState(boolean periodic) {
        // 調(diào)用父類ThreadPoolExecutor中的isRunningOrShutdown方法
        return isRunningOrShutdown(periodic ?
                                   continueExistingPeriodicTasksAfterShutdown :
                                   executeExistingDelayedTasksAfterShutdown);
    }


    /**
     * 是ThreadPoolExecutor中的方法
     * @param shutdownOK 表示線程池能在SHUTDOWN狀態(tài)下運(yùn)行
     */
    final boolean isRunningOrShutdown(boolean shutdownOK) {
        // 線程狀態(tài)
        int rs = runStateOf(ctl.get());
        // 當(dāng)線程是RUNNING狀態(tài),或者是SHUTDOWN狀態(tài)且shutdownOK也為true
        return rs == RUNNING || (rs == SHUTDOWN && shutdownOK);
    }

canRunInCurrentRunState方法就是返回線程池能不能在當(dāng)前狀態(tài)下運(yùn)行。

注: continueExistingPeriodicTasksAfterShutdown與executeExistingDelayedTasksAfterShutdown都是提供給外部設(shè)置。

2.7 ensurePrestart方法

    void ensurePrestart() {
        // 線程池中的線程數(shù)量
        int wc = workerCountOf(ctl.get());
        // 如果小于核心池?cái)?shù)量,就創(chuàng)建新的工作線程
        if (wc < corePoolSize)
            addWorker(null, true);
        // 說明corePoolSize數(shù)量是0,必須創(chuàng)建一個(gè)工作線程來執(zhí)行任務(wù)
        else if (wc == 0)
            addWorker(null, false);
    }

ensurePrestart方法作用:預(yù)先啟動(dòng)工作線程,確保線程池中有工作線程。

三. ScheduledFutureTask類

ScheduledFutureTask是一個(gè)延時(shí)定時(shí)任務(wù),它可以返回任務(wù)剩余延時(shí)時(shí)間,可以被周期性地執(zhí)行。

3.1 重要成員屬性

        /** 是一個(gè)序列,每次創(chuàng)建任務(wù)的時(shí)候,都會自增。 */
        private final long sequenceNumber;

        /** 任務(wù)能夠開始執(zhí)行的時(shí)間 */
        private long time;

        /**
         * 任務(wù)周期執(zhí)行的時(shí)間
         * 0表示不是一個(gè)周期定時(shí)任務(wù)
         * 正數(shù)表示固定周期時(shí)間去執(zhí)行任務(wù)
         * 負(fù)數(shù)表示任務(wù)完成之后,延時(shí)period時(shí)間再去執(zhí)行任務(wù)
         */
        private final long period;

        /** 表示再次執(zhí)行的任務(wù),在reExecutePeriodic中調(diào)用 */
        RunnableScheduledFuture<V> outerTask = this;

        /**
         * 表示在任務(wù)隊(duì)列中的索引位置,用來支持快速從隊(duì)列中刪除任務(wù)。
         */
        int heapIndex;

屬性說明:

  1. sequenceNumber: 是一個(gè)序列,每次創(chuàng)建任務(wù)的時(shí)候,都會自增。
  2. time: 任務(wù)能夠開始執(zhí)行的時(shí)間。
  3. period: 任務(wù)周期執(zhí)行的時(shí)間。0表示不是一個(gè)周期定時(shí)任務(wù)。
  4. outerTask: 表示再次執(zhí)行的任務(wù),在reExecutePeriodic中調(diào)用
  5. heapIndex: 表示在任務(wù)隊(duì)列中的索引位置,用來支持快速從隊(duì)列中刪除任務(wù)。

3.2 構(gòu)造函數(shù)

3.2.1 創(chuàng)建延時(shí)任務(wù)

        /**
         * 創(chuàng)建延時(shí)任務(wù)
         */
        ScheduledFutureTask(Runnable r, V result, long ns) {
            // 調(diào)用父類的方法
            super(r, result);
            // 任務(wù)開始的時(shí)間
            this.time = ns;
            // period是0,不是一個(gè)周期定時(shí)任務(wù)
            this.period = 0;
            // 每次創(chuàng)建任務(wù)的時(shí)候,sequenceNumber都會自增
            this.sequenceNumber = sequencer.getAndIncrement();
        }

         /**
         * 創(chuàng)建延時(shí)任務(wù)
         */
        ScheduledFutureTask(Callable<V> callable, long ns) {
            // 調(diào)用父類的方法
            super(callable);
            // 任務(wù)開始的時(shí)間
            this.time = ns;
            // period是0,不是一個(gè)周期定時(shí)任務(wù)
            this.period = 0;
            // 每次創(chuàng)建任務(wù)的時(shí)候,sequenceNumber都會自增
            this.sequenceNumber = sequencer.getAndIncrement();
        }

3.2.2 創(chuàng)建延時(shí)定時(shí)任務(wù)

        /**
         * 創(chuàng)建延時(shí)定時(shí)任務(wù)
         */
        ScheduledFutureTask(Runnable r, V result, long ns, long period) {
            // 調(diào)用父類的方法
            super(r, result);
            // 任務(wù)開始的時(shí)間
            this.time = ns;
            // 周期定時(shí)時(shí)間
            this.period = period;
            // 每次創(chuàng)建任務(wù)的時(shí)候,sequenceNumber都會自增
            this.sequenceNumber = sequencer.getAndIncrement();
        }

3.3 運(yùn)行任務(wù)run方法

        public void run() {
            // 是否是周期任務(wù)
            boolean periodic = isPeriodic();
            // 如果不能在當(dāng)前狀態(tài)下運(yùn)行,那么就要取消任務(wù)
            if (!canRunInCurrentRunState(periodic))
                cancel(false);
            // 如果只是延時(shí)任務(wù),那么就調(diào)用run方法,運(yùn)行任務(wù)。
            else if (!periodic)
                ScheduledFutureTask.super.run();
            // 如果是周期定時(shí)任務(wù),調(diào)用runAndReset方法,運(yùn)行任務(wù)。
            // 這個(gè)方法不會改變?nèi)蝿?wù)的狀態(tài),所以可以反復(fù)執(zhí)行。
            else if (ScheduledFutureTask.super.runAndReset()) {
                // 設(shè)置周期任務(wù)下一次執(zhí)行的開始時(shí)間time
                setNextRunTime();
                // 重新執(zhí)行任務(wù)outerTask
                reExecutePeriodic(outerTask);
            }
        }

這個(gè)方法會在ThreadPoolExecutor的runWorker方法中調(diào)用,而且這個(gè)方法調(diào)用,說明肯定已經(jīng)到了任務(wù)的開始時(shí)間time了。

  1. 先判斷當(dāng)前線程狀態(tài)能不能運(yùn)行任務(wù),如果不能,就調(diào)用cancel()方法取消本任務(wù)。
  2. 如果任務(wù)只是一個(gè)延時(shí)任務(wù),那么調(diào)用父類的run()運(yùn)行任務(wù),改變?nèi)蝿?wù)的狀態(tài),表示任務(wù)已經(jīng)運(yùn)行完成了。
  3. 如果任務(wù)只是一個(gè)周期定時(shí)任務(wù),那么就任務(wù)必須能夠反復(fù)執(zhí)行,那么就不能調(diào)用run()方法,它會改變?nèi)蝿?wù)的狀態(tài)。而是調(diào)用runAndReset()方法,只是簡單地運(yùn)行任務(wù),而不會改變?nèi)蝿?wù)狀態(tài)。
  4. 設(shè)置周期任務(wù)下一次執(zhí)行的開始時(shí)間time,并重新執(zhí)行任務(wù)。

setNextRunTime設(shè)置任務(wù)下一次執(zhí)行的開始時(shí)間time的方法:

        /**
         * 設(shè)置任務(wù)下一次執(zhí)行的開始時(shí)間time
         */
        private void setNextRunTime() {
            // 周期時(shí)間
            long p = period;
            if (p > 0)
                time += p;
            else
                time = triggerTime(-p);
        }

我們發(fā)現(xiàn)當(dāng)p大于0的時(shí)候,調(diào)用time += p,那么就可能出現(xiàn)計(jì)算后的time可能小于當(dāng)前時(shí)間,因?yàn)槿蝿?wù)執(zhí)行時(shí)間超過了周期時(shí)間p,所以將這個(gè)任務(wù)添加到任務(wù)隊(duì)列中,它就會立即執(zhí)行。
而當(dāng)p小于0的時(shí)候,調(diào)用time = triggerTime(-p)方法,就是在當(dāng)前時(shí)間上,再加上-p的延時(shí)時(shí)間,所以這個(gè)任務(wù)添加到任務(wù)隊(duì)列中,必須延時(shí)-p時(shí)間后,才能執(zhí)行。

reExecutePeriodic重新執(zhí)行任務(wù)的方法:

    /**
     * 重新執(zhí)行任務(wù)task
     */
    void reExecutePeriodic(RunnableScheduledFuture<?> task) {
        // 判斷當(dāng)前線程池狀態(tài)能不能運(yùn)行任務(wù)
        if (canRunInCurrentRunState(true)) {
            // 將任務(wù)添加到任務(wù)隊(duì)列,會根據(jù)任務(wù)延時(shí)時(shí)間進(jìn)行排序
            super.getQueue().add(task);
            // 如果線程池狀態(tài)改變了,當(dāng)前狀態(tài)不能運(yùn)行任務(wù),那么就嘗試移除任務(wù),
            // 移除成功,就取消任務(wù)。
            if (!canRunInCurrentRunState(true) && remove(task))
                task.cancel(false);
            else
                // 預(yù)先啟動(dòng)工作線程,確保線程池中有工作線程。
                ensurePrestart();
        }
    }

這個(gè)方法與delayedExecute方法很像,都是將任務(wù)添加到任務(wù)隊(duì)列中。

  1. 如果當(dāng)前線程池狀態(tài)能夠運(yùn)行任務(wù),那么任務(wù)添加到任務(wù)隊(duì)列。
  2. 如果在在添加任務(wù)的過程中,線程池狀態(tài)是否被別的線程更改了,那么就要進(jìn)行判斷,是否需要取消任務(wù)。
  3. 調(diào)用ensurePrestart()方法,預(yù)先啟動(dòng)工作線程,確保線程池中有工作線程。

3.4 其他重要方法

3.4.1 取消任務(wù)

      public boolean cancel(boolean mayInterruptIfRunning) {
            // 調(diào)用父類的cancel方法取消任務(wù)
            boolean cancelled = super.cancel(mayInterruptIfRunning);
            // 將任務(wù)從任務(wù)隊(duì)列中移除
            if (cancelled && removeOnCancel && heapIndex >= 0)
                remove(this);
            return cancelled;
        }

3.4.2 getDelay方法

        // 返回任務(wù)剩余延時(shí)時(shí)間
        public long getDelay(TimeUnit unit) {
            return unit.convert(time - now(), NANOSECONDS);
        }

3.4.3 compareTo方法

        public int compareTo(Delayed other) {
            if (other == this)
                return 0;
            // 如果是ScheduledFutureTask實(shí)例
            if (other instanceof ScheduledFutureTask) {
                ScheduledFutureTask<?> x = (ScheduledFutureTask<?>)other;
                // 比較任務(wù)開始時(shí)間
                long diff = time - x.time;
                if (diff < 0)
                    return -1;
                else if (diff > 0)
                    return 1;
                // 比較那么任務(wù)是新創(chuàng)建的,因?yàn)樾聞?chuàng)建的sequenceNumber小一點(diǎn)。
                else if (sequenceNumber < x.sequenceNumber)
                    return -1;
                else
                    return 1;
            }
            // 比較任務(wù)的剩余延時(shí)時(shí)間
            long diff = getDelay(NANOSECONDS) - other.getDelay(NANOSECONDS);
            return (diff < 0) ? -1 : (diff > 0) ? 1 : 0;
        }

3.4.4 isPeriodic方法

       /**
         * 是否是周期定時(shí)任務(wù)
         */
        public boolean isPeriodic() {
            return period != 0;
        }

四. 創(chuàng)建延時(shí)定時(shí)線程池

4.1 構(gòu)造函數(shù)

    public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
    }

    public ScheduledThreadPoolExecutor(int corePoolSize,
                                       ThreadFactory threadFactory) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue(), threadFactory);
    }

    public ScheduledThreadPoolExecutor(int corePoolSize,
                                       RejectedExecutionHandler handler) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue(), handler);
    }

    public ScheduledThreadPoolExecutor(int corePoolSize,
                                       ThreadFactory threadFactory,
                                       RejectedExecutionHandler handler) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue(), threadFactory, handler);
    }

都是調(diào)用父類ThreadPoolExecutor構(gòu)造函數(shù)的方法,唯一要注意的地方就是任務(wù)隊(duì)列只能是DelayedWorkQueue實(shí)例,用戶沒有辦法更換ScheduledThreadPoolExecutor的任務(wù)隊(duì)列屬性。

4.2 創(chuàng)建單個(gè)線程的定時(shí)線程池

    public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
        return new DelegatedScheduledExecutorService
            (new ScheduledThreadPoolExecutor(1));
    }

    public static ScheduledExecutorService newSingleThreadScheduledExecutor(
                 ThreadFactory threadFactory) {
        return new DelegatedScheduledExecutorService
            (new ScheduledThreadPoolExecutor(1, threadFactory));
    }

4.3 創(chuàng)建固定數(shù)量的定時(shí)線程池

    public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
    }

    public static ScheduledExecutorService newScheduledThreadPool(
            int corePoolSize, ThreadFactory threadFactory) {
        return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
    }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 【JAVA 線程】 線程 進(jìn)程:是一個(gè)正在執(zhí)行中的程序。每一個(gè)進(jìn)程執(zhí)行都有一個(gè)執(zhí)行順序。該順序是一個(gè)執(zhí)行路徑,或者...
    Rtia閱讀 2,891評論 2 20
  • 線程池中有一定數(shù)量的工作線程,工作線程會循環(huán)從任務(wù)隊(duì)列中獲取任務(wù),并執(zhí)行這個(gè)任務(wù)。那么怎么去停止這些工作線程呢?這...
    wo883721閱讀 1,745評論 0 14
  • 這幾天壬辰反應(yīng)很大,吃不好睡不好,我覺得我很餓可就是吃不下,果果也沒有精力哄了,多虧了婆婆幫我?guī)?。還好果果很...
    瘋瘋之內(nèi)閱讀 366評論 0 1
  • 36kr產(chǎn)品體驗(yàn)報(bào)告 體驗(yàn)環(huán)境 體驗(yàn)機(jī)型:華為榮耀7 體驗(yàn)系統(tǒng):安卓5.0 體驗(yàn)版本:V5.3 一、產(chǎn)品介紹 AP...
    四廢丶閱讀 1,656評論 0 1
  • -----只燈片箋(簡書ID、有讀故事ID、小說閱讀網(wǎng)ID) 或許,因?yàn)槲覀兯幍目臻g是多維度的。 所以,很多話題...
    秭劍執(zhí)一閱讀 1,243評論 2 18

友情鏈接更多精彩內(nèi)容