在面试时,有的面试官就喜欢这种刁钻角度的面试问题,如果你对线程池的任务执行流程熟悉的话,那么该题就不会难住你。所以在开始之前,我们先看下线程池相关的知识。
本文使用 JDK8 演示。
一、概念
线程池是Java中管理和重用线程的一种方式,也是实现并发编程的一种手段。通过使用线程池可以显著提升多线程应用程序的性能。
线程池相对于线程来说,线程池主要解决了两个问题,一个是线程的创建和销毁代价大,另一个就是多线程并发执行时可能导致系统资源不足的问题。
通过线程池,可以提前创建好一组一定数量的线程,并管理好这些线程的生命周期,也就是线程池中线程的存活时间,通过这些我们就可以在有需要的时候重用这些线程,减少创建和销毁线程的开销,提升系统的响应速度和系统资源利用率。
二、线程池工作流程
线程池的任务执行流程是怎么样的呢?
- 首先会判断当前工作线程数量是否大于核心线程数量(corePoolSize),如果小于核心线程数量,直接创建线程执行任务。如果大于核心线程数量,就将任务放入任务队列中进行缓存。
- 判断任务队列容量是否已满,如果不满,任务放入任务队列。
- 如果任务队列满了,判断当前工作线程数量是否大于最大线程数量(maximumPoolSize),如果小于最大线程数量,创建线程执行任务。
- 当工作线程已经大于最大线程了,此时,任务会触发拒绝策略,默认的拒绝策略是抛出异常。
任务工作流程如下图所示:
到了这你心中有结果了吗,是不是线程池会把该任务丢入任务队列呢,不着急,慢慢来,下面我们一起看下源码中是如何判断的。
三、源码分析
1.写个测试方法
在实际的工作中要注意设置线程名称以及拒绝策略哦!
public static void main(String[] args) {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(0,10,1000,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(1000), new NamedThreadFactory("zuiyu",false));
threadPoolExecutor.execute(()->{
System.out.println("醉鱼Java");
});
}
2.Debug 一下
首先我们看一下execute方法就知道是如何了。
通过 debug 发现,当代码运行到图中圈起来的代码这一行时,也就是当工作线程数量为0时,会执行下一步的创建线程执行任务。
最后程序输出了《醉鱼Java》,所以当核心线程设置为 0 的时候,线程池会判断当前工作线程为0 时,会创建线程执行任务。
结论
通过简单的 debug 了一下任务的执行流程,核心线程设置为 0 时,当把任务丢入线程池,还是会把任务丢入任务队列,但是也会在下一步进行判断当前工作线程的线程数量是否为 0,如果为 0,也会创建线程进行执行任务。所以现在你懂了吗?