1,CachedThreadPool 核心线程数为0,最大线程数不限制(最大Integer.MaxValue),内部采用synchrouousQueue 。首先会调用queue的offer方法提交任务,如果有空闲线程则调用poll方法移除线程,交给空闲线程处理,如果没有则创建一个线程,调用poll方法移除。任务执行完成后,阻塞到queue上等待任务,如果超过60s,则自动销毁该线程。
特点:无需放入等待队列,任务即来即处理,适合处理大量、耗时少的任务。适用追求响应速度的任务,不缓存到队列直接创建线程处理。
2,FixThreadPool 、SingleThreadPool 核心线程数为n个或1个,最大线程数为n个或1个。即最多只支持n或1个线程去处理线程池的任务。阻塞队列是LinkedBlockQueue,他是一个无界队列。
总结:建议自定义线程池的参数,CachedThreadPool因为最大线程不受限制,如果是非常耗时的任务,就会一直创建线程去执行,很有可能导致CPU百分百;
定长的线程池因为使用无界队列,同样如果是遇到耗时的任务,那么就会把任务持续不断的堆积到队列中,极有可能导致OutOfMermory。
思考:自定义线程池的各个参数时,要综合考虑任务时CPU密集型还是IO密集型的任务,阻塞队列尽量选择有界队列,最大线程数要做限制(也不能设置太小,直接给拒绝服务了。。),当超出系统可接受的负载时,设置合理的拒绝策略直接不予处理;
对于极耗时的任务来说,使用单独的线程池去处理,与其他任务区分开。
CPU密集型的任务,一般来说不要设置过多线程,因为线程频繁切换会有非常大的开销(尤其是在单处理的cpu上。。。);IO密集型的任务可以设的大一点,充分使用CPU多核的优势。(线程切换基于时间片轮转)
参考:具体的线程池设计参考美团技术:https://tech.meituan.com/2020/04/02/java-pooling-pratice-in-meituan.html (该篇文章着重讲解了线程池参数化配置在不同场景下很难有一个统一的方案去处理设置,那么可以基于监控去做一套动态配置的基础设施出来,从降低线程池参数修改的成本以及多维度监控这两个方面降低了故障发生的概率)