1、如何合理地选择或者配置
CachedThreadPool用于并发执行大量短期的小任务,或者是负载较轻的服务器。
FixedThreadPool 用于负载比较重的服务器,为了资源的合理利用,需要限制当前线程数量。
SingleThreadExecutor 用于串行执行任务的场景,每个任务必须按顺序执行,不需要并发执行。
ScheduledThreadPoolExecutor 用于需要多个后台线程执行周期任务,同时需要限制线程数量的场景。
2、Executor 中submit 和execute区别
execute和submit的区别在于submit会返回Future来获取任何执行的结果, submit方便Exception处理。
3、一般根据任务类型进行区分, 假设CPU为N核
CPU密集型任务需要减少线程数量, 降低线程之间切换造成的开销, 可配置线程池大小为N + 1.
IO密集型任务则可以加大线程数量, 可配置线程池大小为 N * 2.
混合型任务则可以拆分为CPU密集型与IO密集型, 独立配置.
4、保存待执行任务的阻塞队列
ArrayBlockingQueue:基于数组、有界,按 FIFO(先进先出)原则对元素进行排序
LinkedBlockingQueue:基于链表,按FIFO (先进先出) 排序元素
吞吐量通常要高于 ArrayBlockingQueue
Executors.newFixedThreadPool() 使用了这个队列
SynchronousQueue:不存储元素的阻塞队列
每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态
吞吐量通常要高于 LinkedBlockingQueue
Executors.newCachedThreadPool使用了这个队列
PriorityBlockingQueue:具有优先级的、无限阻塞队列
5、队列饱和策略
CallerRunsPolicy:只要线程池没关闭,就直接用调用者所在线程来运行任务
AbortPolicy:直接抛出 RejectedExecutionException 异常
DiscardPolicy:悄悄把任务放生,不做了
DiscardOldestPolicy:把队列里待最久的那个任务扔了,然后再调用 execute() 试试看能行不,我们也可以实现自己的 RejectedExecutionHandler 接口自定义策略,比如记录日志