实际业务中的程序总是会使用多线程,线程池则是多线程资源管理最常用的方式。
线程池类ThreadPoolExecutor构造方法中有七个参数,具体如下:
- int corePoolSize:核心线程数量,默认情况下,即时没有任务,线程池也会维持核心线程不被销毁;
- int maximumPoolSize:最大线程数量,当没有空闲线程可用时,线程池会创建新线程来执行任务,线程总数不会超过此属性;
- long keepAliveTime:线程空闲时间,超过该时间后,线程池会销毁线程,默认情况下,核心线程不会被销毁;
- TimeUnit unit:线程空闲时间的时间单位;
- BlockingQueue workQueue:任务缓存队列,当线程数已达最大数量,且没有空闲线程时,新任务会入队等待;
- ThreadFactory threadFactory:创建线程使用的线程工厂,其中可以设置线程名称,方便在日志中排查问题;
- RejectedExecutionHandler handler:拒绝策略,当任务缓存队列满后,新收到的任务会交由拒绝策略处理。
需要特别注意的是,最后三个属性应当按照实际业务需求进行实例化,而非使用Executors提供的默认实现。
阅读类或方法的JavaDoc注释可以快速了解其功能和使用方式,但如果想具体了解其逻辑,学习其中的实现方法,看源码是最好的选择,下面以ThreadPoolExecutor类中的增加新线程的addWorker方法为例做源码分析(Java8):
private boolean addWorker(Runnable firstTask, boolean core) {
//响应continue retry
retry:
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
//多种不允许创建新线程的情况
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
for (;;) {
//不能超过最大线程数
int wc = workerCountOf(c);
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
//线程总数+1,在线程创建前先检查总数是否合法,减少开销
if (compareAndIncrementWorkerCount(c))
break retry;
c = ctl.get(); // Re-read ctl
if (runStateOf(c) != rs)
continue retry;
//compareAndIncrementWorkerCount方法失败后重试
}
}
//开始创建工作线程
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
w = new Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
//先持有锁,再创建线程
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
int rs = runStateOf(ctl.get());
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
//检查线程是否已经已启动
if (t.isAlive())
throw new IllegalThreadStateException();
workers.add(w);
int s = workers.size();
//线程池运行时的最大并发任务数
if (s > largestPoolSize)
largestPoolSize = s;
workerAdded = true;
}
} finally {
mainLock.unlock();
}
//启动线程
if (workerAdded) {
t.start();
workerStarted = true;
}
}
} finally {
//增加线程失败,把开始时调用compareAndIncrementWorkerCount增加的值再减掉
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}