为什么需要线程池?
线程的时间构成:
- 创建时间
- 运行时间
- 销毁时间
线程的创建、销毁是非常耗时的,可能比实际执行任务的运行时间还要长。
Thread 通过 new 来新建一个线程,初始化一些线程信息,例如线程名称、ID、所属组等等,调用 start 后JVM为其创建方法栈、程序计数器。可以看到这个过程还是比较复杂的,如果需要的线程比较多,那么频繁的创建和销毁就会对性能产生很大的影响。
线程池就是对一定数量的线程保持其存活状态,不让其销毁,有新的任务来了就直接调用空闲线程来执行,这样就可以提升线程的运行效率。
线程池的工作过程
image
执行一个任务时,判断当前正在运行的线程的数量是否小于 corePoolSize,是,马上创建线程运行任务,否,将任务放入队列。
如果任务队列满了,判断当前运行的线程的数量是否小于 maximumPoolSize,是,创建辅助线程运行任务,否,执行拒绝处理任务时的策略。
当一个线程执行完当前任务后,会从队列取下一个任务执行,如果一个线程没有任务可做了,并且空闲时间超过了 keepAliveTime,判断当前线程数是否大于 corePoolSize,是,结束此线程,最终会收缩到 corePoolSize 的大小。
代码
image
ThreadPoolExecutor 是核心类:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
其参数配合上面的工作过程理解。