![](https://img-blog.csdnimg.cn/img_convert/30e20edbd3bbce3b802a051b0606b412.png)
前言
在java后端面试中线程池肯定是逢考必问了。主要有两个原因,第一个是常用。因为代码规范已经写明自己维护线程有一定危险性,所以不建议使用,线程池就变得不可替代。每次我们业务需要做什么都免不了开一个线程池做异步,或者执行任务。第二个是它有很多细节,平时如果不仔细阅读源码是很难有体会的,当然不包括用写的教训换来的线上线程池故障带来的深刻思考。当然用这种经验换来惊醒代价是很高的。所以平时我们还要注意积累关于线程池的内容。
今天就从一下几方面梳理线程池面试的方方面面,这些都是我面试碰到的问题。整理如下
![](https://img-blog.csdnimg.cn/img_convert/883632c5c74be0f9aac3ff9f181edb3b.png)
一、线程池参数
创建线程池的参数如下:
1、核心线程数
2、最大线程数
3、阻塞队列
4、线程超时时间
5、线程创建工厂类
![](https://img-blog.csdnimg.cn/img_convert/98708ec4531b4fcbb9b4f10c376a5ec7.png)
小考点1、线程数如何设置
如果是cpu密集型的,线程数的构建是核心线程数+2
如果是io密集型,线程数就要2*核心数
这些都是理论值,真正需要设置多少还要依据我们最终的qps目标和线上服务器性质两者结合,并通过实际压测结果获得。
小考点2、线程工厂需要为线程设置名称
线上一单出问题,不给线程起名字很难判断出是哪个线程池出了问题。尤其是项目比较庞大,线程池较多的情况。
小考点3、阻塞队列
阻塞队列不要使用那些大小不限制的阻塞队列,因为随着线程膨胀是增长会导致整个服务被拖垮,出现oom。
二、线程池阻塞队列
线程池涉及到阻塞队列,所以很容易深入到阻塞队列这块去考。
例如阻塞队列有哪些,每种阻塞队列的特点是什么?如何根据场景去选择阻塞队列。
![](https://img-blog.csdnimg.cn/img_convert/b0b3e59417badad22267d4ad155d59a5.png)
熟记这些阻塞队列平时根据场景加以应用。
三、线程池两种关闭
线程池关闭有两种方式
第一种是:shutdownNow()
1、设置线程池状态为stop。原子类型ctl设置为SOTP。
2、为所有线程池中运行的线程设置中断信号量。
3、排空所有等待执行的任务,将其返回给请求关闭线程池的线程。
这三个步骤都是在获取了可重入锁mainLock的前提下。
线程池不在接受新的任务,同时篱笆关闭线程池,线程池里面的任务不再被执行,而是交给了请求关闭线程池的线程。
第二种:shutdown()
1、设置线程池状态为stop。原子类型ctl设置为SOTP。
2、获取各个任务的锁,如果获取到了,说明线程空闲,给对该线程发中断。如果获取不到则忽略。worker线程感知了中断,
3、调用tryTerminate
3.1、设置ctl为TIDYING,
3.2、为所有任务线程发送信号量,关闭空闲线程。
四、线程池线程回收
线程池拒绝接受新的任务,同时等线程池里面任务执行完毕再关闭线程池。
![](https://img-blog.csdnimg.cn/img_convert/41476fb9b7f4b0e30ba98c3de7265001.png)
线程池中每一个线程在调用getTask方法的时候都要走上面这段代码。这段代码的意思是如果
ctl的状态为SHUTDOWN、STOP、TIDYING,TERMINATED;
或者
ctl状态是STOP、TIDYING,TERMINATED,且任务队列为空则将工作线程数减去1,并为线程返回任务为null。这个时候该线程会退出循环退出。执行以下内容
![](https://img-blog.csdnimg.cn/img_convert/bc6abc00e23c54afb46cb357301785e4.png)
图1
1、给其他空闲线程池发送中断信号
2、如果线程池要求保留最小核心数的线程,如果当前线程池线程小于核心线程数,会再为线程池补充线程。
五、非线程池中线程回收。
如果让你手撕一个线程的时候一定要把线程中断也考虑进去。
![](https://img-blog.csdnimg.cn/img_convert/03a02c032f897188a1006a9dbc03557f.png)
图2
例子1
![](https://img-blog.csdnimg.cn/img_convert/b210455047c1ec89c4e2e1bdbfb19b4a.png)
图3
我介绍下我在框架里面看到实现优雅关闭的方式
1、添加ShutdownHook
工程项目里面常用,通过关闭钩子先项目关闭的时候会调用到钩子,这样我们可以将关闭线程池的动作放置到这里面去。
![](https://img-blog.csdnimg.cn/img_convert/3748b2a6f35f0a004a2ae5513b12a1d4.png)
通常是使用一下三个步骤实现优雅关闭
![](https://img-blog.csdnimg.cn/img_convert/037b176e5aeefbe18e4eef647415d594.png)
参考文献
线程池的关闭_早起的虫子jj的博客-CSDN博客_线程池关闭
终止线程 4 种方式_Been~You的博客-CSDN博客_终止线程的方法有哪些