Java8 ScheduledThreadPoolExecutor 源码解析

  目录

一、ScheduledFutureTask

 1、定义

2、compareTo / getDelay / isPeriodic

3、run / cancel

二、DelayedWorkQueue

1、定义

2、add / put / offer

3、peek / poll / take

 4、remove / clear / drainTo

5、iterator /  Itr

三、ScheduledThreadPoolExecutor 

1、定义

2、schedule / scheduleAtFixedRate / scheduleWithFixedDelay

3、submit / execute 

4、shutdown/ shutdownNow / onShutdown


    本篇博客来详细探讨延期执行或者周期性执行任务的线程池ScheduledThreadPoolExecutor的实现细节。

一、ScheduledFutureTask

 1、定义

     ScheduledFutureTask是ScheduledThreadPoolExecutor的内部类,表示一个延期执行的任务,其类继承关系如下:

 

其中ScheduledFuture接口的定义如下:

Delayed接口的含义可以参考之前的《Java8 LinkedBlockingQueue和DelayQueue 源码解析》 

RunnableScheduledFuture接口的定义如下:

该类包含的属性如下:

        //原子递增生成的一个序列号
        private final long sequenceNumber;

        //执行该任务的开始时间,以纳秒为单位
        private long time;

        //重复执行下一次任务的间隔时间,单位是纳秒,如果是正值则表示是固定的速率执行
        //如果是负值,则表示以固定的延时执行,如果0则表示不需要重复执行
        private final long period;

        //周期执行时将此实例再次添加到任务队列中,从而能够被再次执行
        RunnableScheduledFuture<V> outerTask = this;

        //用于保存当前实例在DelayedWorkQueue数组中的索引,方便从数组中移除的时候可以快速定位
        int heapIndex;

 该类的构造方法如下:

       ScheduledFutureTask(Runnable r, V result, long ns) {
            super(r, result);
            this.time = ns;
            this.period = 0;
            //sequencer是ScheduledThreadPoolExecutor的属性
            this.sequenceNumber = sequencer.getAndIncrement();
        }

        
        ScheduledFutureTask(Runnable r, V result, long ns, long period) {
            super(r, result);
            this.time = ns;
            this.period = period;
            this.sequenceNumber = sequencer.getAndIncrement();
        }

       
        ScheduledFutureTask(Callable<V> callable, long ns) {
            super(callable);
            this.time = ns;
            this.period = 0;
            this.sequenceNumber = sequencer.getAndIncrement();
        }

2、compareTo / getDelay / isPeriodic

     这三个方法用于实现RunnableScheduledFuture接口的

public long getDelay(TimeUnit unit) {
            //获取剩余的有效期,大于0表示延时未到,不能执行
            return unit.convert(time - now(), NANOSECONDS);
        }

public int compareTo(Delayed other) {
            if (other == this) // compare zero if same object
                return 0;
            if (other instanceof ScheduledFutureTask) {
                ScheduledFutureTask<?> x = (ScheduledFutureTask<?>)other;
                //比较两者的执行起始时间
                long diff = time - x.time;
                if (diff < 0)
                    return -1;
                else if (diff > 0)
                    return 1;
                //起始时间一致,则比较序列号    
                else if (sequenceNumber < x.sequenceNumber)
                    return -1;
                else
                    return 1;
            }
            //如果不是ScheduledFutureTask实例,则比较剩余的有效期
            long diff = getDelay(NANOSECONDS) - other.getDelay(NANOSECONDS);
            return (diff < 0) ? -1 : (diff > 0) ? 1 : 0;
        }

//判断是否周期执行的任务        
public boolean isPeriodic() {
            return period != 0;
        }

final long now() {
        return System.nanoTime();
    }

3、run / cancel

     这两个方法改写了父类FutureTask的实现,其中run方法是实现任务周期性执行的核心,如下:

public boolean cancel(boolean mayInterruptIfRunning) {
            //调用父类方法取消该任务
            boolean cancelled = super.cancel(mayInterruptIfRunning);
            //removeOnCancel是ScheduledThreadPoolExecutor的属性,默认为false
            //heapIndex大于等于0说明该Task还在DelayedWorkQueue中
            if (cancelled && removeOnCancel && heapIndex >= 0)
                remove(this); //从任务队列中将其移除
            return cancelled;
        }

public void run() {
            //是否周期执行的
            boolean periodic = isPeriodic();
            if (!canRunInCurrentRunState(periodic)) //如果当前线程池不能执行该任务,则取消
                cancel(false);
            else if (!periodic) //非周期执行任务,调用父类的run方法
                ScheduledFutureTask.super.run();
            else if (ScheduledFutureTask.super.runAndReset()) { //runAndReset方法正常执行后不保存结果,不更新状态
                //重新计算下一次运行的起始时间
                setNextRunTime();
                //将outerTask提交到任务队列,outerTask通常就是this,从而实现周期性执行
                reExecutePeriodic(outerTask);
            }
        }

boolean canRunInCurrentRunState(boolean periodic) {
        return isRunningOrShutdown(periodic ?
                                   continueExistingPeriodicTasksAfterShutdown :
                                   executeExistingDelayedTasksAfterShutdown);
    }

final boolean isRunningOrShutdown(boolean shutdownOK) {
        int rs = runStateOf(ctl.get());
        return rs == RUNNING || (rs == SHUTDOWN && shutdownOK);
    }

private void setNextRunTime() {
            long p = period;
            if (p > 0) //固定速率的,不考虑执行任务本身的耗时
                time += p;
            else
                //p小于0,固定延时的
                time = triggerTime(-p);
        }

long triggerTime(long delay) {
        //当前时间加上固定延时,如果delay大于Long的最大值的一半,则走后面的overflowFree
        return now() +
            ((delay < (Long.MAX_VALUE >> 1)) ? delay : overflowFree(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;
    }

void reExecutePeriodic(RunnableScheduledFuture<?> task) {
        if (canRunInCurrentRunState(true)) {
            super.getQueue().add(task);//将该任务添加到任务队列中
            //再次检查当前线程池是否可以执行任务,如果不能则将其从任务队列移除并取消掉
            if (!canRunInCurrentRunState(true) && remove(task))
                task.cancel(false);
            else 
                //可以正常执行,尝试增加一个执行任务的线程
                ensurePrestart();
        }
    }

二、DelayedWorkQueue

1、定义

     DelayedWorkQueue是ScheduledThreadPoolExecutor的内部类,是一个先进先出的,自动扩容的且支持排序的阻塞队列,用于保存延迟执行的任务ScheduledFutureTask

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值