ScheduledThreadPoolExecutor源码解析

ScheduledThreadPoolExecutor使用

public class ScheduledThreadPoolExecutorTest {

    /**
     * 创建核心线程数为5 给定的延迟之后运行任务, 或者定期执行任务的线程池 工作队列 使用延迟队列 DelayedWorkQueue
     */
    private static ScheduledExecutorService newScheduledThreadPool = Executors.newScheduledThreadPool(5);


    public static void main(String[] args) {
        /**
         * 有延迟的, 周期性执行异步任务
         * 本例子为: 延迟1秒, 每2秒执行1次
         */
        newScheduledThreadPool.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                System.out.println("this is " + Thread.currentThread().getName());
            }

        }, 10, 2, TimeUnit.SECONDS);
        /**
         * 延迟10s 只执行一次
         */
        newScheduledThreadPool.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("this is " + Thread.currentThread().getName());
            }
        },10,TimeUnit.SECONDS);

        /**
         * 延迟3s 每下一次执行按照执行时间+delay
         */
        newScheduledThreadPool.scheduleWithFixedDelay(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("this is " + Thread.currentThread().getName());
            }
        },10,3,TimeUnit.SECONDS);

    }
}

ScheduledThreadPoolExecutor 源码

schedule 方法

 public <V> ScheduledFuture<V> schedule(Callable<V> callable,
                                           long delay,
                                           TimeUnit unit) {
        if (callable == null || unit == null)
            throw new NullPointerException();
        RunnableScheduledFuture<V> t = decorateTask(callable,
            new ScheduledFutureTask<V>(callable,
                                       triggerTime(delay, unit))); //构造ScheduledFutureTask任务  triggerTime 计算任务延迟时间
        delayedExecute(t);//任务执行主方法
        return t;
    }

scheduleAtFixedRate 方法

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();
       构建RunnableScheduledFuture任务类型       
        ScheduledFutureTask<Void> sft =
            new ScheduledFutureTask<Void>(command,
                                          null,
                                          triggerTime(initialDelay, unit), //计算任务的延迟时间
                                          unit.toNanos(period)); //计算任务的执行周期
        RunnableScheduledFuture<Void> t = decorateTask(command, sft);
        sft.outerTask = t;//赋值给outerTask,准备重新入队等待下一次执行
        delayedExecute(t);//执行任务
        return t;
    }

scheduleWithFixedDelay 方法

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();
            //构建RunnableScheduledFuture任务类型
        ScheduledFutureTask<Void> sft =
            new ScheduledFutureTask<Void>(command,
                                          null,
                                          triggerTime(initialDelay, unit),//计算任务的延迟时间
                                          unit.toNanos(-delay));//计算任务的执行周期 此处传 负数
        RunnableScheduledFuture<Void> t = decorateTask(command, sft);
        sft.outerTask = t;
        delayedExecute(t);//执行任务
        return t;
    }

delayedExecute 方法

 private void delayedExecute(RunnableScheduledFuture<?> task) {
        if (isShutdown()) //如果线程池状态不是RUNNING 状态 则采用拒绝策略拒绝任务
            reject(task);
        else {
            super.getQueue().add(task); //将任务添加到延迟队列中
              //如果当前状态无法执行任务,则取消
            if (isShutdown() &&
                !canRunInCurrentRunState(task.isPeriodic()) &&
                remove(task))
                task.cancel(false);
            else
             //增加Worker,确保提交的任务能够被执行
               ensurePrestart(); 
        }
    }

canRunInCurrentRunState 方法

 public boolean isPeriodic() {
            return period != 0;
}

 boolean canRunInCurrentRunState(boolean periodic) { 
//  只有这个 schedule 方法 会 使periodic =true
         //continueExistingPeriodicTasksAfterShutdown //关闭后继续执行已经存在的周期任务 
       //executeExistingDelayedTasksAfterShutdown  //关闭后继续执行已经存在的延时任务
        return isRunningOrShutdown(periodic ?
                                   continueExistingPeriodicTasksAfterShutdown :
                                   executeExistingDelayedTasksAfterShutdown);
    }

ensurePrestart 方法

 void ensurePrestart() {
        int wc = workerCountOf(ctl.get()); //获取当前线程数
        if (wc < corePoolSize)//当前线程小于核心线程数
            addWorker(null, true); // 创建核心线程 
        else if (wc == 0)
            addWorker(null, false);//创建非核心线程
    }

我们知道addWorker() 方法会启动线程,所有接下来我们应该查看run()方法

run方法

public void run() {
            //是否为周期任务 判断period 是否为0 
            boolean periodic = isPeriodic();
            if (!canRunInCurrentRunState(periodic)) //当前状态是否可以执行
                cancel(false);
            else if (!periodic) //如果不是周期性任务 直接执行
                ScheduledFutureTask.super.run();
            else if (ScheduledFutureTask.super.runAndReset()) { // 此处会调用业务方法。如果成功runAndRest,则设置下次运行时间并调用reExecutePeriodic。
                setNextRunTime();
                reExecutePeriodic(outerTask);
            }
        }

setNextRunTime 方法

private void setNextRunTime() {
            long p = period;
            if (p > 0) //固定速率执行,scheduleAtFixedRate
                time += p;
            else
                time = triggerTime(-p); //固定延迟执行,scheduleWithFixedDelay
}

long triggerTime(long delay) {
    /*
     * 如果delay < Long.Max_VALUE/2,则下次执行时间为当前时间+delay。
     *
     * 否则为了避免队列中出现由于溢出导致的排序紊乱,需要调用overflowFree来修正一下delay(如果有必要的话)。
     * */
        return now() +
            ((delay < (Long.MAX_VALUE >> 1)) ? delay : overflowFree(delay));
    }
/**
 * 主要就是有这么一种情况:
 * 某个任务的delay为负数,说明当前可以执行(其实早该执行了)。
 * 工作队列中维护任务顺序是基于compareTo的,在compareTo中比较两个任务的顺序会用time相减,负数则说明优先级高。
 *
 * 那么就有可能出现一个delay为正数,减去另一个为负数的delay,结果上溢为负数,则会导致compareTo产生错误的结果。
 *
 * 为了特殊处理这种情况,首先判断一下队首的delay是不是负数,如果是正数不用管了,怎么减都不会溢出。
 * 否则可以拿当前delay减去队首的delay来比较看,如果不出现上溢,则整个队列都ok,排序不会乱。
 * 不然就把当前delay值给调整为Long.MAX_VALUE + 队首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))
            delay = Long.MAX_VALUE + headDelay;
    }
    return delay;
    }

reExecutePeriodic 方法

void reExecutePeriodic(RunnableScheduledFuture<?> task) {
      if (canRunInCurrentRunState(true)) {//池关闭后可继续执行
        super.getQueue().add(task);//任务重新入列
        //重新检查run-after-shutdown参数,如果不能继续运行就移除队列任务,并取消任务的执行
        if (!canRunInCurrentRunState(true) && remove(task))
            task.cancel(false);
        else
            ensurePrestart();//启动一个新的线程等待任务
    }
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值