这篇是并发编程系列文章第五篇了,说到并发编程,怎么少的了线程池,在阿里线程池使用场景非常多,用好线程池这个利器也算是日常开发必须掌握的了,下面讲讲2019年的那一夜,就线程池和某位面试官鏖战了半个小时。
面试官 : 看你简历上写了对系统性能做了优化,能简单给我介绍一下吗? 都有哪些优化,你是怎么衡量优化效果的?
我 : 巴拉巴拉。。。例如我们系统之前要查询用户的个人身份信息、联系人信息、订单状态信息、积分信息,之前系统是单线程串行处理的,我用线程池对四个任务并行处理,然后对处理结果合并。
面试官 : 你刚才说用到线程池,能跟我讲讲为什么用线程池吗? 我创建四个线程处理可不可以?
我 : 可以,当然可以。
我 : 但是用线程池更合适。阿里巴巴开发规约中有一条:
3.【强制】线程资源必须通过线程池提供,不允许在应用中自行显式创建线程。
说明:使用线程池的好处是减少在创建和销毁线程上所消耗的时间以及系统资源的开销,解决资源不足的问题。如果不使用线程池,有可能造成系统创建大量同类线程而导致消耗完内存或者“过度切换”的问题。
我 : 就像你去餐厅吃饭,服务员总是提前洗好盘子,不会等你来打饭的时候才洗盘子,盘子就像是线程池里的线程,你打饭就是要处理的任务。
面试官 : 那你知道线程池的类结构吗?
我: 这算什么问题? 不应该是问我核心线程数怎么设置吗?好吧。。。请看下图:
Executor 的定义非常简单,就定义了线程池最本质要做的事,执行任务。
public interface Executor { void execute(Runnable command); }
ExecutorService 也是个接口,不过他算是把线程池的框架搭出来了,告诉要实现它的线程池必须提供的一些管理线程池的方法。
AbstractExecutorService 是普通的线程池执行器,ScheduledExecutorService 是定时任务线程池。
面试官 : 那你日常开发中是怎么创建线程池的?
我: 我用ThreadPoolExecutor 自定义创建线程池。
面试官 : 那你知道线程池创建时都有哪些参数吗?
我: 线程池主要的核心参数有7个,我们看 ThreadPoolExecutor 构造函数就知道了
corePoolSize :核心线程数
maximumPoolSize: 最大线程数
keepAliveTime :线程在线程池中不被销毁的空闲时间,如果线程池的线程太多,任务比较小,到这个时间就销毁线程池。
unit : keepAliveTime 的时间单位,一般设置成秒或毫秒。
workQueue : 任务队列,存放等待执行的任务
threadFactory: 创建线程的任务工厂,比如给线程命名加上前缀,后面会讲
handler : 拒绝任务处理器,当任务处理不过来时的拒绝处理器
allowCoreThreadTimeOut : 是否允许核心线程超时销毁,这个参数不在构造函数中,但重要性也很高
面试官 : 老实说,你是不是来之前背过了,不然怎么可能都记住了。
我: [掀桌子],不面了,还找什么工作,要什么自行车。
我不过是来之前把“安琪拉的博客”公众号上的文章都看了个遍。
面试官 : 其实刚才那也是问题,考察面试者是否皮实,我们继续。。
面试官 : 刚才说了这些核心参数,你能不能跟我讲讲线程池的基本工作原理。
我: 可以的,这里我给你画个流程,如下所示: