回答
ThreadPoolExecutor
使用 corePoolSize
和 maximumPoolSize
控制核心线程数和最大线程数。初始时,线程池会创建核心线程数(corePoolSize
)的线程来处理任务。当任务被提交到线程池后,线程池会首先尝试使用空闲的核心线程执行任务,如果没有空闲的核心线程,则任务会被放入任务队列(workQueue
)。工作线程会从任务队列中获取任务执行,从而避免频繁创建和销毁线程。
那线程是如何实现复用的呢?在 ThreadPoolExecutor#runWorker()
方法中,工作线程会不断地从任务队列(workQueue
)中获取任务,当一个线程执行完任务后,线程并不会直接退出,而是采用死循环的方式不断从任务队列中获取新的任务执行,只要任务队列中有任务,那么该线程就会一直执行下去。同时,调用它的方式并不是通过 Thread#start()
的方式,而是直接调用它的 run()
,这样把 run()
方法当做普通方法去调用执行业务逻辑,而不是通过调用 Thread#start()
去创建新的线程,从而实现线程复用。
扩展
我们直接看源码吧。
调用 execute()
方法 :
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
// 小于 corePoolSize
if (addWorker(command, true))
return;
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) {
// 大于 corePoolSize 且加入任务队列成功
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);
}
这里的核心方法就是调用 addWorker()
,那 addWorker()
的作用是什么呢?它的作用是在线程池中创建一个线程并执行第一个参数传入的任务,它的第二个参数是 boolean,用于判断校验值是使用 corePoolSize
还是 maxPoolSize
。该方法我们只需要关注后面一段:
private boolean addWorker(Runnable firstTask, boolean core) {
// 省略代码
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
//将 firstTask 包装成一个 Worker
w = new Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
// 省略代码
if (workerAdded) {
t.start();
workerStarted = true;
}
}
} finally {
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}