通过 Executors 工具可以创建普通的线程池以及schedule调度任务的调度池。
来看下内部是怎么实现的
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
ThreadPoolExecutor
Executors 只是提供了几个常用的 ThreadPoolExecutor 构造方法。完全可以直接声明 ThreadPoolExecutor。先看下 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;
}
threadFactory:是构造Thread的方法,可以自己去包装和传递,主要实现newThread方法即可。
Rejected handler:提交新Runnable时,如果线程池已关闭或运行线程数已经达到 maximumPoolSize,就会调用丢弃处理方法。默认提供了5种丢弃处理的方法:
ThreadPoolExecutor.AbortPolicy
ThreadPoolExecutor.CallerRunsPolicy
ThreadPoolExecutor.DiscardPolicy
ThreadPoolExecutor.DiscardOldestPolicy
workQueue/corePoolSize/maximumPoolSize
在提交新 Runnable 时,如果当前运行的线程数小于 corePoolSize,就会新建thread。如果当前运行的线程数达到了corePoolSize,会向workQueue中增加线程,如果workQueue满了,就会新建线程,只到运行线程数达到maximumPoolSize,这时就会根据丢弃策略进行处理。
如果使用无边界的队列(LinkedBlockingQueue),那么运行线程数就不会大于corePoolSize,maximumPoolSize就不起作用了。
如果使用有边界的队列(ArrayBlockingQueue),队列大小与 maximumPoolSize 共同作用。大队列加小maximumPoolSize 可以减少运行线程数,降低资源消耗,同时也降低了吞吐量。小队列加大maximumPoolSize,可以增加吞吐量,但要小心过高的资源占用,也会影响吞吐量。
keepAliveTime 当运行线程数超过corePoolSize时,超过的线程如果休眠时间超过 keepAliveTime,就会被终止。默认情况下keepAliveTime只在运行线程数超过corePoolSize时起作用,如果设置allowCoreThreadTimeOut(true),就会影响核心运行线程。