前言
池化技术在很多领域都有应用,比如数据库连接池,HTTP连接池以及线程池。实际上都是预先建立一些连接缓存,有具体的任务时就可以直接分配,减少新建立资源时的消耗,提供更快的响应速度。
基本原理
jdk1.8中封装了Executors
工具类作为初始化线程池的入口。该类提供好几种线程池初始化方法。我就简单研究了public static ExecutorService newFixedThreadPool(int nThreads)
方法。
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
线程池实际上的管理都是ThreadPoolExecutor
类完成的。
值得注意的是传递参数默认的任务队列可用容量为Integer.MAX_VALUE
,所以有资源耗尽的风险[JavaGuide]
public LinkedBlockingQueue() {
this(Integer.MAX_VALUE);
}
对于一次申请线程池资源基本流程如下:1. 如果没有达到设置最大线程数,新建线程执行;2. 如果线程数目已经是设置的最大值,则尝试加入任务队列;3. 如果加入任务队列失败,则再次尝试分配新线程,若失败则说明线程池达到饱和状态(saturated
)。
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
/*
* Proceed in 3 steps:
*
* 1. If fewer than corePoolSize threads are running, try to
* start a new thread with the given command as its first
* task. The call to addWorker atomically checks runState and
* workerCount, and so prevents false alarms that would add
* threads when it shouldn't, by returning false.
*
* 2. If a task can be successfully queued, then we still need
* to double-check whether we should have added a thread
* (because existing ones died since last checking) or that
* the pool shut down since entry into this method. So we
* recheck state and if necessary roll back the enqueuing if
* stopped, or start a new thread if there are none.
*
* 3. If we cannot queue task, then we try to add a new
* thread. If it fails, we know we are shut down or saturated
* and so reject the task.
*/
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
else if (!addWorker(command, false))
reject(command);
}
通过制定的饱和策略reject(command)
final void reject(Runnable command) {
handler.rejectedExecution(command, this);
}
默认handler
为AbortPolicy()
。参考其他饱和策略[JavaGuide]
private static final RejectedExecutionHandler defaultHandler =
new AbortPolicy();
在研究addWorker()
时,还注意到了Java中标签跳出多重循环的应用(goto)。
此外,线程池管理实际上还有很多内容,比如线程池状态管理和生命周期等。一篇来自美团的干货文章献上[美团技术团队]。