Executor以及Executors源码分析

基于JDK1.8源码进行分析的。

首先我们看一下Executor接口的源码。

public interface Executor {
    void execute(Runnable command);
}

该接口定义了一个规范,也就是execute方法的规范,里面需要传入Runnable类或者其子类的对象。该接口有一个实现接口,ExecutorService。下面我们看一下该接口的源码。

public interface ExecutorService extends Executor {

    void shutdown();

    List<Runnable> shutdownNow();

    boolean isShutdown();

    boolean isTerminated();

    boolean awaitTermination(long timeout, TimeUnit unit)
        throws InterruptedException;

    <T> Future<T> submit(Callable<T> task);

    <T> Future<T> submit(Runnable task, T result);

    Future<?> submit(Runnable task);

    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
        throws InterruptedException;

    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
                                  long timeout, TimeUnit unit)
        throws InterruptedException;

    <T> T invokeAny(Collection<? extends Callable<T>> tasks)
        throws InterruptedException, ExecutionException;

    <T> T invokeAny(Collection<? extends Callable<T>> tasks,
                    long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

相比Executor,该ExecutorService接口定义了更多的规范,里面有两个核心方法,分别是:

  1. Future<?> submit(Runnable task);
  2. <T> Future<T> submit(Callable<T> task);

两者的区别在于是否有返回结果,很明显,Callable有返回结果。他们的相同点在于都返回一个Future对象。Future对象可以阻塞线程直到运行完毕(获取结果,如果有的话),也可以取消任务执行,当然也能够检测任务是否被取消或者是否执行完毕。在没有Future之前我们检测一个线程是否执行完毕通常使用Thread.join()或者用一个死循环加状态位来描述线程执行完毕。现在有了更好的方法能够阻塞线程,检测任务执行完毕甚至取消执行中或者未开始执行的任务。

ScheduledExecutorService接口定义了一些方法或者说是规范。下面是关于这个接口的源码。

public interface ScheduledExecutorService extends ExecutorService {

    public ScheduledFuture<?> schedule(Runnable command,
                                       long delay, TimeUnit unit);

    public <V> ScheduledFuture<V> schedule(Callable<V> callable,
                                           long delay, TimeUnit unit);

    public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
                                                  long initialDelay,
                                                  long period,
                                                  TimeUnit unit);

    public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
                                                     long initialDelay,
                                                     long delay,
                                                     TimeUnit unit);

}

一共有四个方法,都是方便用户针对执行时间,进行更细化的操作和控制。看到这里我想到了定时JOB,一共有以下几种方式进行创建。

  1. 多线程
  2. 线程池
  3. Timer/TimerTask
  4. spring的框架quartz
  5. springBoot自带的Schedule

一共有以上几种实现方式,而ScheduledExecutorService接口里面定义的方法,很类似于Timer/TimerTask的使用。

ThreadPoolExecutor是ExecutorService的一个实现,当然是继承自AbstractExecutorService抽象类。

public class ThreadPoolExecutor extends AbstractExecutorService

ScheduledThreadPoolExecutor是继承自ThreadPoolExecutor,实现了ScheduledExecutorService接口。

public class ScheduledThreadPoolExecutor
        extends ThreadPoolExecutor
        implements ScheduledExecutorService

 总结来看如下图:

说了这么多还没扯到正题,因为配置一个线程池还是需要了解很多的,比如说:策略等,并且有时候我们即使配置了,但不一定是最优的。我们都知道java一般都会定义一些工具类方法,方便用户操作。比如常见到的有:Arrays、Collections、Objects等。我们的Executor也有一个工具类,叫做Executors。一般我们也是通过该类来创建线程池,既方便用户创建,也方便用户进行操作。该工具类中我们常用的有五种线程池,分别如下:

  1. newSingleThreadExecutor:创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。
  2. newFixedThreadPool:创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。
  3. newCachedThreadPool:创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小
  4. newScheduledThreadPool:创建一个大小无限制的定时线程池。此线程池支持定时以及周期性执行任务的需求。
  5. newSingleThreadScheduledExecutor:创建一个单线程的定时线程池。此线程池支持定时以及周期性执行任务的需求。

下面我们分别看一下这五个方法。

newSingleThreadExecutor

创建一个单线程的线程池。

public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }
public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>(),
                                    threadFactory));
    }

newFixedThreadPool

 创建固定大小的线程池。

public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>(),
                                      threadFactory);
    }

newCachedThreadPool

创建一个可缓存的线程池。

public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>(),
                                      threadFactory);
    }

newScheduledThreadPool

创建一个大小无限制的定时线程池。

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

newSingleThreadScheduledExecutor

创建一个单线程的定时线程池。

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

总体来看,分别都是有一个重载方法,一个方法用来默认创建,或者指定参数,另外一个重载方法都是通过ThreadFactory进行创建,而且很明显可以看出,基本一种类型的线程池会有对应的实现方式,实现类。

关于线程池的状态,源码中有如下内容:

RUNNING:  Accept new tasks and process queued tasks
SHUTDOWN: Don't accept new tasks, but process queued tasks
STOP:     Don't accept new tasks, don't process queued tasks,
         and interrupt in-progress tasks
TIDYING:  All tasks have terminated, workerCount is zero,
          the thread transitioning to state TIDYING
          will run the terminated() hook method
TERMINATED: terminated() has completed

可以看到一共有五种状态可以看到。

  1. Running:接收新的任务,处理队列任务。
  2. Shutdown:不接受新任务,但处理队列任务。
  3. Stop:不接受新任务,不处理队列任务,并且中断正在执行的任务。
  4. Tidying:所有的任务都终止。转换到状态TIDYING的线程将运行terminate()钩子方法
  5. Terminated:terminated()已经完成。

下面我们看一下状态转化:

RUNNING -> SHUTDOWN

为了避免理解产生偏差,以下是源码中的注释内容。

 On invocation of shutdown(), perhaps implicitly in finalize()

在调用shutdown()时,可能隐含在finalize()中

(RUNNING or SHUTDOWN) -> STOP

On invocation of shutdownNow()

 当调用shutdownNow()

SHUTDOWN -> TIDYING

When both queue and pool are empty

当队列,线程池都空的时候

STOP -> TIDYING

When pool is empty

当线程池空的时候

TIDYING -> TERMINATED

When the terminated() hook method has completed

当terminated()钩子函数调用完成的时候

这么看可能比较笼统,我们下面用图表示一下。

我觉得还算比较清晰。

下篇我们先分析一下ThreadPoolExecutor源码。这篇先到这里。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值