Executor.java
该接口主要定义将任务提交到线程池的接口方法,为什么在该接口中只定义任务的提交方法,在jdk文档中也给了一个大致的说明(该接口只负责任务提交到线程池,与具体线程池如何执行提交的任务解耦)
ExecutorService
该类主要定义了线程池的关闭方式,以及在Executor的基础之上封装了更多类型的任务提交方式,主要有两种方式:一种是单个任务提交执行;一种是批量任务的提交执行,如:
- 单个任务提交方式
submit(Runnable task):这种方式返回一个future,调用者可以通过该future控制提交任务的执行过程,并且可以通过该返回实例,同步的等待任务的执行结果。
submit(Runnable task, T result):这种方式是,当任务成功的执行完成的时候,future.get()返回的是result
多任务提交方式 - 列表内容
invokeAll(Collection<Runnable> tasks...)
:该接口会等待tasks所有任务完成之后才返回。
invokeAny(Collection<Runnable> tasks...)
:该接口是,在提交的tasks所有任务中,只要有一个任务完成,这个接口就返回。
ThreadPoolExecutor
该线程池类是使用较多的线程池类,该线程池有两种任务处理的方式:
1、当新的任务被添加到该线程池中的时候,线程池中的线程如果达到了配置的数量之后,且没有空闲的线程的时候,新的任务将被加入到任务队列中。
2、当新的任务到达之后,线程池中如果没有空闲的线程,那么线程池会创建新的线程来执行任务。
在创建该线程池的时候需要传入较多的参数,主要包含如下几个参数:
int corePoolSize
:线程池中的核心线程数量。当新任务到达的时候,如果线程池中的可用的线程数量小于 corePoolSize
的时候,会创建新的线程来执行任务;如果线程池中的可用的线程数量大于等于>= corePoolSize
的时候,如果workQueue仍然可以插入任务的时候,线程池不会创建新的线程,如果workQueue不能插入任务了,且当前线程数量小于< maximumPoolSize
的时候,线程池会创建新的线程池来处理任务,否则就会抛出RejectedExecutionException。
int maximumPoolSize
:当前线程池中允许的最大的线程数量,如果workQueue不能加入新的任务,而且当前线程池中的线程数量等于=maximumPoolSize的时候,会抛出RejectedExecutionException。
long keepAliveTime
:当线程池中的线程数量大于corePoolSize,且部分线程空闲的时候,当空闲的线程空闲时间超过该值得时候,空闲的线程将会被销毁。
TimeUnit unit
:标志keepAliveTime的单位,SECONDE、MINITES…,最终该时间会被转换为纳秒
BlockingQueue<Runnable> workQueue
:用于缓存任务的任务队列。
ThreadFactory threadFactory
:线程池工厂,可以通过自定义线程池工厂,提前创建部分线程,从而达到prestartAllCoreThreads的功能(因为该功能在线程池中必须保证workQueue中有corePoolSize这么多的任务)
RejectedExecutionHandler handler
:当任务不能被接受的时候的回掉函数。
Executors.java
该类是线程池的工厂类,主要负责线程池的创建,主要通过调用线程池的具体的实现类进行线程池的创建。
使用注意
1、如果你的任务与任务之间有相互的依赖关系,或者是存在锁的竞争关系的时候,建议使用Executors.newCachedThreadPool();,因为该线程池会对每个任务创建一个线程,不会导致由于任务不能被执行而引起的死锁。
2、如果你的任务是独立的任务,即任务之间没有依赖关系,那么可以使用Executors.newFixedThreadPool(int nThreads),这样效率更高,因为固定的线程数量使得线程调度的频率低,线程切换开销小。
jdk中其他类型的线程池的实现,如批量任务线程池,延迟任务线程池等,将在下一节中进行深入的剖析,当然这些线程池也是可以基于上述的ThreadPoolExecutor实现。