在java 5中引入了Executor框架实现对线程池的管理,放在java.util.cocurrent目录下,通过这个这个框架来实现线程的启动,执行和关闭,可以简化并发编程的操作。
Executor框架包含线程池,Executor,Executors,ExecutorService,CompletionService,Future,Callable 等。
Executors提供了一系列创建线程池的接口,返回的线程池都实现了ExecutorService接口。
public static ExecutorService newFixedThreadPool(int nThreads)
创建固定数目线程的线程池。新来的任务首先检查是否有空闲线程,有的话使用那个线程进行调度,没有的话将任务放在队列中等待。任务调度没有超时时间,任务队列为list
public static ExecutorService newCachedThreadPool()
创建一个可缓存的线程池,调用execute将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线 程并添加到池中。终止并从缓存中移除那些已有 60 秒钟未被使用的线程。默认线程的最大数为整数的最大值,适合短时间调度的任务。
public static ExecutorService newSingleThreadExecutor()
创建一个单线程化的Executor。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
创建一个支持定时及周期性的任务执行的线程池,多数情况下可用来替代Timer类。
这四种方法都是用的 Executors 中的 ThreadFactory 建立的线程
public ThreadPoolExecutor (int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,BlockingQueue<Runnable> workQueue)
-
corePoolSize:线程池中所保存的核心线程数,包括空闲线程。
-
maximumPoolSize:池中允许的最大线程数。
-
keepAliveTime:线程池中的空闲线程所能持续的最长时间。
-
unit:持续时间的单位。
- workQueue:任务执行前保存任务的队列,仅保存由 execute 方法提交的 Runnable 任务。
根据 ThreadPoolExecutor 源码前面大段的注释,我们可以看出,当试图通过 excute 方法讲一个 Runnable 任务添加到线程池中时,按照如下顺序来处理:
-
如果线程池中的线程数量少于 corePoolSize,即使线程池中有空闲线程,也会创建一个新的线程来执行新添加的任务;
-
如果线程池中的线程数量大于等于 corePoolSize,但缓冲队列 workQueue 未满,则将新添加的任务放到 workQueue 中,按照 FIFO 的原则依次等待执行(线程池中有线程空闲出来后依次将缓冲队列中的任务交付给空闲的线程执行);
-
如果线程池中的线程数量大于等于 corePoolSize,且缓冲队列 workQueue 已满,但线程池中的线程数量小于 maximumPoolSize,则会创建新的线程来处理被添加的任务;
- 如果线程池中的线程数量等于了 maximumPoolSize,有 4 种才处理方式(该构造方法调用了含有 5 个参数的构造方法,并将最后一个构造方法为 RejectedExecutionHandler 类型,它在处理线程溢出时有 4 种方式,这里不再细说,要了解的,自己可以阅读下源码)。