线程池的本质是通过预先创建一批线程,当有任务加入时直接使用预先创建的线程处理任务,一方面避免了即时创建线程带来的性能损耗,另一方面也可以更好的管理整个应用的线程使用情况,列如控制最大线程数、任务排队等。
一个线程的生命周期为:
新建 ---> 运行 ---> 阻塞 ---> 死亡当一个线程执行完后会进入到死亡状态,这个时候线程就不存在了,那么 JDK 中的线程池是如何“复用”一个线程的呢?
答案是 ThreadPoolExecutor 中的 keepAliveTime 参数,它的作用是控制 ThreadPoolExecutor 中 Worker 工作线程从工作队列中获取任务的超时时间,当工作队列中没有任务时,将会阻塞,直到满足 keepAliveTime 超时时间后进入到死亡状态。
换句话说 keepAliveTime 参数会将线程状态保存在阻塞状态,从而等待执行后续加入到工作队列的任务以完成线程复用的目的。
try {
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r;
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}代码上使用了 BlockingQueue 阻塞队列来存储工作任务,使用 poll(keepAliveTime) 阻塞方法来获取工作任务。
当然如果在 keepAliveTime 后依旧没有任务,当前线程依旧会进入到死亡状态,后续加入的任务会有线程池中其它线程或者创建新的线程来执行。