一、引言
提到 Java 线程池,就不得不说 ThreadPoolExecutor,它是 Java 并发包 java.util.concurrent 中的一个类,提供一个高效、稳定、灵活的线程池实现,用于实现多线程并发执行任务,提高应用程序的执行效率。
在《任务执行与Executor框架》中,Huazie 介绍了通过 java.util.concurrent.Executors 中的静态工厂方法来创建线程池,而这个线程池实现就是 ThreadPoolExecutor 。
ThreadPoolExecutor 提供了一系列参数和配置选项,开发人员可以根据应用的需求来定制线程池的行为。
本篇就将详细介绍线程池 ThreadPoolExecutor 中的各种配置参数。
二、主要内容
注意: 以下涉及代码,均来自 JDK 1.8,其他版本如有出入,请自行查看
2.1 核心构造函数
话不多说,先来查看 ThreadPoolExecutor 的核心构造函数:
上述构造函数中的 7 个参数就是下面将要重点介绍的线程池 ThreadPoolExecutor 的核心配置参数了。
2.2 核心线程数
private volatile int corePoolSize;
corePoolSize 变量就是 核心线程数,即在没有设置allowCoreThreadTimeOut 为 true 的情况下,需要保持存活的最小工作线程数量。
翻看 ThreadPoolExecutor 的 execute(Runnable command) 方法的源码,如下:
上述截图代码可以看出: 如果运行的线程数少于核心线程数,则为当前任务启动一个新的核心线程。
调用 addWorker 方法会原子性地检查 runState 和 workerCount,从而防止在不应该添加线程时发出错误警报【这时 addWorker 方法会返回 false】。
可以通过 setCorePoolSize(int corePoolSize) 方法来重新设置核心线程数,如下图所示:
setCorePoolSize 方法将覆盖构造函数中设置的核心线程数。如果新值小于当前值,多余的现有线程将在它们下次变为空闲时被终止。如果新值更大,将根据需要启动新线程来执行任何排队的任务。
2.3 最大线程数
private volatile int maximumPoolSize;
maximumPoolSize 变量就是线程池允许的最大线程数。
可以通过 setMaximumPoolSize(int maximumPoolSize) 方法来重新设置线程池允许的最大线程数,如下图所示:
setMaximumPoolSize 方法将覆盖构造函数中设置的最大线程数。如果新值小于当前值,多余的现有线程将在它们下次变为空闲时被终止。
2.4 空闲线程存活时间
private volatile long keepAliveTime;
keepAliveTime 变量就是空闲线程存活时间【即空闲线程等待工作的超时时间(以纳秒为单位)】。当线程池中的线程数量超过 核心线程数 或者 允许核心线程超时 时,线程将使用此超时时间。否则,它们将无限期地等待新工作。
可以通过 setKeepAliveTime(long time, TimeUnit unit) 方法来重新设置空闲线程存活时间,如下图所示:
setKeepAliveTime 方法会覆盖在构造函数中设置的空闲线程存活时间。如果当前池中有多于核心数量的线程,在等待这段时间而没有处理任务之后,多余的线程将会被终止。
2.5 keepAliveTime 的时间单位
long keepAliveTime;
TimeUnit unit;
// 空闲线程等待工作的超时时间
this.keepAliveTime = unit.toNanos(keepAliveTime);
2.6 核心线程在空闲时的回收策略
private volatile boolean allowCoreThreadTimeOut;
如果为 false(默认值),即使核心线程处于空闲状态,它们也会保持活动状态。
如果为 true,核心线程会使用 keepAliveTime 来设置等待工作的超时时间。
可以通过 ThreadPoolExecutor 的 allowCoreThreadTimeOut(boolean value) 方法进行设置。
2.7 工作队列
private final BlockingQueue<Runnable> workQueue;
workQueue 变量就是工作队列,它是一个阻塞队列,用于保存等待执行的任务并将其交给工作线程处理。
2.8 线程工厂
private volatile ThreadFactory threadFactory;
threadFactory 变量就是线程工厂,所有线程都是使用这个工厂创建的(通过 addWorker 方法),默认使用 Executors.defaultThreadFactory() 来创建线程。
2.9 拒绝策略
private volatile RejectedExecutionHandler handler;
handler 变量就是 拒绝策略,即当执行过程中饱和或关闭时调用的处理程序。
当阻塞队列已满且无法创建新的线程时,线程池会调用拒绝策略来处理新提交的任务。
Java 线程池提供了几种不同的拒绝策略实现,如
AbortPolicy:默认策略,直接抛出 RejectedExecutionException 异常,阻止系统正常运行。
CallerRunsPolicy:只用调用者运行一些任务,如果线程池已满,则将任务回退到调用者执行。
DiscardOldestPolicy:抛弃最老的任务请求,也就是即将被执行的任务。
DiscardPolicy:直接丢弃任务,不给予任何处理,也不抛出异常。