ScheduledThreadPoolExecutor源码主要部分解析

Posted 菜鸟麦迪粉

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ScheduledThreadPoolExecutor源码主要部分解析相关的知识,希望对你有一定的参考价值。

ScheduledThreadPoolExecutor继承与基础线程池类ThreadPoolExecutor并实现ScheduledExecutorService接口。

其中ScheduledExecutorService继承与ExecutorService接口并添加了scheduleAtFixedRate和scheduleWithFixedDelay等方法。

两个方法的区别是前者是周期性的按照一定的时间进行任务的执行。如果一个任务执行超过了周期时间,则任务执行完之后会马上进行下一次任务的执行。而后者在这样的情况出现的时候会在任务执行完之后仍然间隔周期时间进行下一次任务的执行。

 

ScheduledThreadPoolExecutor内部封装了一个ScheduledFutureTask<V>类。该类继承与FutureTask<V>实现RunnableScheduledFuture<V>

ScheduledFutureTask<V>内部有对应的任务的比较器。包含sequenceNumber记录任务进入队列的序号。内部的关键方法为runPeriodic()方法

 

private void runPeriodic() {  

  •             boolean ok = ScheduledFutureTask.super.runAndReset();  
  •             boolean down = isShutdown();  
  •             // Reschedule if not cancelled and not shutdown or policy allows  
  •             if (ok && (!down ||  
  •                        (getContinueExistingPeriodicTasksAfterShutdownPolicy() &&  
  •                         !isStopped()))) {  
  •                 long p = period;  
  •                 if (p > 0)  
  •                     time += p;  
  •                 else  
  •                     time = now() - p;  
  •                 ScheduledThreadPoolExecutor.super.getQueue().add(this);  
  •             }  
  •             // This might have been the final executed delayed  
  •             // task.  Wake up threads to check.  
  •             else if (down)  
  •                 interruptIdleWorkers();  
  •         }  
  •   

该方法处理周期性执行的和非周期性执行的任务。其中period传入的值有正有负。这也是scheduleAtFixedRate和scheduleWithFixedDelay对应的区别。最后将相应的任务加入到对应的线程池的阻塞队列中。如果线程池关闭了需要调用对应的线程池关闭的处理。

对应的run方法为:

public void run() {  

  •             if (isPeriodic())  
  •                 runPeriodic();  
  •             else  
  •                 ScheduledFutureTask.super.run();  
  •         }  

 private void delayedExecute(Runnable command) {
        if (isShutdown()) {
            reject(command);
            return;
        }
        if (getPoolSize() < getCorePoolSize())
            prestartCoreThread();

        super.getQueue().add(command);
    }
首次将任务加入到队列中的方法。

 public boolean prestartCoreThread() {
        return addIfUnderCorePoolSize(null);
    }


    private boolean addIfUnderCorePoolSize(Runnable firstTask) {
        Thread t = null;
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            if (poolSize < corePoolSize && runState == RUNNING)                

               t = addThread(firstTask);        

            } finally {            

                        mainLock.unlock();        

                 }        

               if (t == null)            

                        return false;         t.start();         return true; }

如果当前线程数小于核心线程数。则会新创建一个线程。新创建线程的时候会传入首个任务。

ScheduledThreadPoolExecutor中的默认拒绝策略是AbortPolicy 当任务添加到线程池中被拒绝时,它将抛出 RejectedExecutionException 异常 其它的拒绝策略为:

AbortPolicy         -- 当任务添加到线程池中被拒绝时,它将抛出 RejectedExecutionException 异常。
CallerRunsPolicy    -- 当任务添加到线程池中被拒绝时,会在线程池当前正在运行的Thread线程池中处理被拒绝的任务。
DiscardOldestPolicy -- 当任务添加到线程池中被拒绝时,线程池会放弃等待队列中最旧的未处理任务,然后将被拒绝的任务添加到等待队列中。
DiscardPolicy       -- 当任务添加到线程池中被拒绝时,线程池将丢弃被拒绝的任务。

 

 

 

以上是关于ScheduledThreadPoolExecutor源码主要部分解析的主要内容,如果未能解决你的问题,请参考以下文章