ScheduledThreadPoolExecutor类自我理解

       

目录

1、ScheduledThreadPoolExecutor 结构:

1.1、ScheduledFuture类

1.2、ScheduledThreadPoolExecutor 构造器

2、 ScheduledFutureTask 结构

2.1、ScheduledFutureTask字段

2.2、ScheduledFutureTask 构造器

2.3、ScheduledFutureTask 相关方法介绍

        2.3.1、isPeriodic()

        2.3.2、run(),重头

3、DelayedWorkQueue 阻塞队列

4、执行实现流程


        根据Timer类可知,得有优先级任务队列queue,延迟任务task,执行方法。        

ScheduledThreadPoolExecutor 也是这样,不过其优先级阻塞队列是 DelayedWorkQueue

, 定期任务是ScheduledFutureTask,执行是ThreadPoolExecutor。

1、ScheduledThreadPoolExecutor 结构:

public class ScheduledThreadPoolExecutor
        extends ThreadPoolExecutor //继承了线程池,那么初始化,方法调用等可以直接复用
        implements ScheduledExecutorService { 
        //实现了 ScheduledExecutorService 接口,接口定义了 schedule 、 scheduleAtFixedRate 、 scheduleWithFixedDelay 三类方法,见名知意,分别为定时任务一次性任务,固定速率 和 固定间隔,返回值都为 
        ScheduledFuture类

1.1、ScheduledFuture类

        

        extends Delayed, Future<V>类,可以拿去任务执行返回值 Future接口的get方法,是否结束等等,以及接口 Delayed 的 getDelay(TimeUnit unit) 获取任务的 延迟时间方法。

1.2、ScheduledThreadPoolExecutor 构造器

        一共由有4个构造器,选参数多的说明。

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

    //super 调用父类ThreadPoolExecutor中的构造器如下

    
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

        corePoolSize: 线程池中线程的数量。

        ThreadFactory: 工厂用何种方式创建一个线程。

        RejectedExecutionHandler: 由于达到线程边界和队列满了,那么要阻止执行使用的处理方式。

        具体应用实现以下代码供参考:

        return new ScheduledThreadPoolExecutor(10,
                new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build(),
                new ThreadPoolExecutor.CallerRunsPolicy())
        {
            @Override
            protected void afterExecute(Runnable r, Throwable t)
            {
                super.afterExecute(r, t);
                Threads.printException(r, t);
            }
        };

2、 ScheduledFutureTask 结构

       ScheduledFutureTask是 ScheduledThreadPoolExecutor的私有内部类,其相当于Timer类中的TimerTask,用于定义任务相关。其结构如下图所示:

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

其还是需要覆盖 FutureTask 的run() 方法,implements RunnableScheduledFuture 接口,需要实现其isPeriodic()方法。下面一个一个解释,先看字段

2.1、ScheduledFutureTask字段

        


        /** 断开FIFO连接的序列号 */
        private final long sequenceNumber;

        /** 任务何时执行,单位是纳秒 */
        private long time;

        /**
         * 0是一次性(非重复)任务,正值固定速率,负值固定间隔。
         */
        private final long period;

        /** 实际运行的任务,定期任务需要重新加入队列,指向当前任务对象 */
        RunnableScheduledFuture<V> outerTask = this;

        /**
         * 索引到阻塞队列中,以支持更快的cancel()操作。
         */
        int heapIndex;

        其中主要关注运行时间time,时间间隔period,当前任务outerTask;

2.2、ScheduledFutureTask 构造器

        

         /**
         * 创建一个一次性任务,此时period为0,time时间单位为纳秒
         */
        ScheduledFutureTask(Runnable r, V result, long ns) {
            super(r, result);
            this.time = ns;
            this.period = 0;
            this.sequenceNumber = sequencer.getAndIncrement();
        }

        /**
         * 创建一个定期执行任务,super(r,result)也是将Runnable和返回值结合,拼成一个callable
         */
        ScheduledFutureTask(Runnable r, V result, long ns, long period) {
            super(r, result);
            this.time = ns;
            this.period = period;
            this.sequenceNumber = sequencer.getAndIncrement();
        }

2.3、ScheduledFutureTask 相关方法介绍

        2.3.1、isPeriodic()

        /**
         * 判断一个任务是否是定期任务,还是一次性任务,通过period字段判断
         */
        public boolean isPeriodic() {
            return period != 0;
        }

        2.3.2、run(),重头

          

        /**
         * 重写了FutureTask的run()方法,任务执行主体
         */
        public void run() {
            boolean periodic = isPeriodic();
            if (!canRunInCurrentRunState(periodic))//判断任务是否能在当前线程池状态下运行
                cancel(false);
            else if (!periodic) //不是定期任务,是一次性任务,那么执行
                ScheduledFutureTask.super.run();
            else if (ScheduledFutureTask.super.runAndReset()) { //此时条件一定是定期任务,runAndSet()会执行run()方法,确保任务任务执行不止一次
                setNextRunTime();//设置下一次执行任务时间
                reExecutePeriodic(outerTask); //将任务重新插入队列
            }
        }
    }

        private void setNextRunTime() {
            long p = period;
            if (p > 0)
                time += p;
            else
                time = triggerTime(-p);
        }

        void reExecutePeriodic(RunnableScheduledFuture<?> task) {
        if (canRunInCurrentRunState(true)) { //当前状态可以运行,加入到队列中
            super.getQueue().add(task);
            if (!canRunInCurrentRunState(true) && remove(task))
                task.cancel(false);
            else
                ensurePrestart(); //确保能启动,线程池相关
        }
    }

3、DelayedWorkQueue 阻塞队列

        

         

    //只能往队列添加RunnableScheduledFutures类,其implements Runnbale接口
    static class DelayedWorkQueue extends AbstractQueue<Runnable>
        implements BlockingQueue<Runnable> {}

        就是往优先级阻塞队列中添加,删除,获取,消费 RunnableScheduledFutures对象,需要搭配 ThreadPoolExecutor 一起使用。ThreadPoolExecutor的 getTask()方法会调用 DelayedWorkQueue 中的 take()方法,消费一个阻塞队列中的最先执行对象。感觉有点复杂,不想写。

        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)
                            available.await();
                        else {
                            Thread thisThread = Thread.currentThread();
                            leader = thisThread;
                            try {
                                available.awaitNanos(delay);
                            } finally {
                                if (leader == thisThread)
                                    leader = null;
                            }
                        }
                    }
                }
            } finally {
                if (leader == null && queue[0] != null)
                    available.signal();
                lock.unlock();
            }
        }

4、执行实现流程

        通过创建一个ScheduledThreadPoolExecutor对象,此时阻塞队列也初始化了。然后调用其对应方法,以ScheduledThreadPoolExecutor 对象的 schedule()方法为例,需要传参为 一个Runnable任务,延迟时间执行,时间单位,此时为一次性任务,和scheduleAtFixedRate() 、scheduleWithFixedDelay() 相差不多。

       创建一个 ScheduledFutureTask 任务,通过decorateTask 修饰为  RunnableScheduledFuture 接口类,然后调用 delayedExecute()方法,将延迟执行任务加入阻塞队列。等待ThreadPoolExecutor执行getTask方法。因为初始化对象ScheduledThreadPoolExecutor时,实际上是创建ThreadPoolExecutor 对象,其字段keepAliveTime为0,直接调用getTask()方法了,然后走DelayedWorkQueue阻塞队列的take()消费一个队列中的对象。

    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) {
        if (isShutdown())
            reject(task);
        else {
            //加入阻塞队列,等待执行
            super.getQueue().add(task);
            if (isShutdown() &&
                !canRunInCurrentRunState(task.isPeriodic()) &&
                remove(task))
                task.cancel(false);
            else
                ensurePrestart();
        }
    }

  • 14
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值