本文属于对Java线程池的综合思考,如果您对Java线程池还不太了解,可以先收藏。
本文讲解如下几个内容:
题外话:做技术这一行,一定要沉的住气,把细节想透。
这里要分为2种情况来看:JDK的和Tomcat(Dubbo也可以设置)的。
为什么要如此设计了?我对此的理解如下所示:
Tomcat
大多处理的是IO密集型
任务,线程大多数时候都是在阻塞在IO操作上,无事可做。与其如此,不如索性多创建线程,让CPU
把时间片分给其他线程做后续操作。基于此考虑,优先创建线程。
实际项目中,因为临时线程不好控制,大多数建议核心线程和临时线程设置成一样大小,这种情况下,二者的表现其实是一致的了。
JDK下的临时线程创建是在:新任务加入时,队列已被填满,同时核心线程数没有达到最大线程数的时候。
那么创建后临时线程如何进行工作:
pool(time,unit)
的方式从队列中拉活干,干完1个任务继续干下一个任务,不会马上被销毁。。pool(time,unit)
超过一定时间没有拉到活干,那么该临时线程被销毁(饿死了)这个地方有个理解误区:临时线程的创建仅仅是为了应付队列满后新加入的那个任务,其实不是的,临时线程创建后,不仅仅处理一个任务,会不提的从队列中poll活出来干。
当某一个核心线程干完活后,会通过take
阻塞的形式从任务队列中拉取任务,如果没有就会一直阻塞在那里,标准的生产者和消费者问题。
临时线程则是通过poll(time,unit)
的方式拉活来干的。
临时线程如果在指定的时间内没有通过poll(time,unit)
拉到活干,那么就会被清理掉。
核心线程了?
核心线程默认是不允许被销毁的,不过如果通过poolExecutor.allowCoreThreadTimeOut(true);
进行设置,当核心线程超过在构造函数定义的超时时间后,仍然会被销毁,官方doc说明如下。
/**
* Core pool size is the minimum number of workers to keep alive
* (and not allow to time out etc) unless allowCoreThreadTimeOut
* is set, in which case the minimum is zero.
*/
private volatile int corePoolSize;
我感觉我应该抽时间,把官方的doc好好读读。
通常情况下,我们认为只有1种,就是在:队列满了+核心线程与临时线程之后等于最大值时,又有任务加入就会触发。
但是还有一种情况,就是调用shutdown
后,线程池会将正在执行的任务执行完毕后才真正退出,此时如果再加入了一个任务,也会触发拒绝策略。
以下内容肯定很多瑕疵!
这个命题太大了,完全够写一篇文章了,个人技术和见识还有限,此处只能记录一些我知道的关于核心线程数的知识。
N+1
。N为CPU核心。2N+1
第三个公式,其中每个参数如何获取了?任务处理时间可以通过运行多次任务取平均的方式获取,CPU利用率?任务等待时间了?还请知道的小伙伴不吝赐教。
个人感觉应该看业务形态,业务看重吞吐量还是时延,通过测试来得到。
核心线程增多,吞吐量是先上升后下降?
核心线程增多,时延保持稳定然后再下降?
上述理论个人猜想,等这段时间忙完了,好好测试下!
有些时候面试官会问题,线程池有那几个参数,不需要死记硬背,通过理解来记忆。
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)