Java线程池配置由繁至简,找到适合自己的天命线程池(二)
文章摘要
GPT 4
此内容根据文章生成,并经过人工审核,仅用于文章内容的解释与总结
前提知识 🧀
上一篇我们简单介绍了下线程池的一些基本内容,不清楚或者想回顾的同学可以点进主页里查看,或者后面把链接 🔗 贴在评论里。我们这篇主要来解决上一篇最后提出的问题:根据项目,自己来设置合适的参数。这个合适到底要怎么来定义?且往下看。
任务队列 workQueue 和饱和策略 handler 什么时候登场?
首先这里有几道经常考的线程池面试题:
- 简单介绍下线程池,核心数从 corePoolSize 到 maximumPoolSize 的变化过程?
- 线程池在什么时机会执行饱和策略?
- 当线程池的任务队列满之后,就会执行对应的饱和策略吗?
这些问题其实说到底都是在考线程池的执行步骤,当你弄懂这些时机和条件后,我相信你可以融会贯通整套流程。
我们这里先引入流程图看一下:
只看流程图可能不容易理解,我们下面用一个示例来演示一下整个流程:
首先我们假设几个参数,corePoolSize 核心线程为 5,maximumPoolSize 最大线程数为 10,workQueue 任务队列的容量为 20,还需要用 activeCount 来表示正在工作的线程(下面简写为工作线程),为了兜底,所以假设任务一直在添加,由于很耗时,程序 hold 不住,一直到执行饱和策略的环节。
- 假设不断地有任务进来,程序就会增加工作线程来处理任务,即 activeCount 增加,会一直增加到 corePoolSize,直到满足第一个条件“核心线程池已满”,即 activeCount=corePoolSize=5。
- 这时再追加任务,程序就会把任务放进任务队列 workQueue,工作线程处理完当前任务,就会按 FIFO 先入先出的顺序,从任务队列 workQueue 里拿出任务继续做;随着任务的放入,workQueue.size()会逐渐增大,一直到满足第二个条件“任务队列已满”,即 workQueue.size()=20,activeCount 此时仍为 5。
- 再继续追加任务,程序就会在 corePoolSize 的基数上继续增加工作线程,即 activeCount 从 5 开始增加,一直到满足第三个条件“最大线程池已满”,即 activeCount=maximumPoolSize=10。
- 此时我们看一下参数值,activeCount=maximumPoolSize=10,workQueue.size()=20,能满的已经全满了,表示程序已经达到了最大的上限,后面再追加的任务就会去执行饱和策略。
饱和策略有哪些?哪个更适合我?
我们先来回顾下饱和策略的意义——由于达到线程边界和队列容量而阻塞执行时使用的处理程序。
可以简单地用一句话来解释:任务队列满 & 工作线程数已经增加到最大核心数,此时再新增进任务,便会对任务执行对应的处理。
AbortPolicy
Abort->退出、终止;满足条件时会直接抛出 RejectedExecutionException 异常,它也是 ThreadPoolExecutor 默认的饱和策略;但同时由于他的简单粗暴,程序可能会因此中断,所以虽然是默认的饱和策略,但如果要用,务必做好异常处理。
CallerRunsPolicy
满足条件时,会直接调用当前主线程去执行任务,比如你在 main 方法执行了线程池,策略的缺点就是可能会阻塞主线程,影响性能。