面试题答案
一键面试线程池参数理解
- 核心线程数
- 线程池在初始化后,会创建核心线程数数量的线程并保持这些线程处于活动状态。即使这些线程处于空闲状态,它们也不会被销毁(除非设置了 allowCoreThreadTimeOut 为 true)。核心线程就像是线程池的常驻部队,随时准备执行任务。
- 最大线程数
- 线程池允许创建的最大线程数量。当任务队列已满且核心线程都在忙碌时,线程池会尝试创建新的线程,直到线程数量达到最大线程数。如果此时任务队列仍然满且无法再创建新线程,新提交的任务将会根据拒绝策略进行处理。
- 队列容量
- 用于存放待执行任务的队列。当核心线程都在执行任务时,新提交的任务会被放入队列中等待执行。队列的容量决定了能缓存多少任务,不同类型的队列(如 ArrayBlockingQueue、LinkedBlockingQueue 等)在性能和特性上有所不同。例如,ArrayBlockingQueue 是有界队列,容量固定;LinkedBlockingQueue 可以是有界或无界队列。
根据业务场景调整参数优化性能
- I/O密集型任务
- 核心线程数:I/O 操作通常会有大量时间处于等待 I/O 完成的阻塞状态,这段时间线程可以去处理其他任务。因此,核心线程数可以设置得相对较大,一般可以设置为 CPU 核心数的 2 倍甚至更多。例如,如果 CPU 是 4 核,核心线程数可以设置为 8 或 10。这样可以充分利用 CPU 资源,在等待 I/O 的间隙执行其他任务,提高整体的吞吐量。
- 最大线程数:可以适当比核心线程数大一些,因为 I/O 密集型任务在等待 I/O 时,系统资源相对充裕,可以容纳更多线程。但也不宜过大,避免过多线程带来的上下文切换开销。可以设置为核心线程数的 1.5 倍左右。例如核心线程数为 8,最大线程数可设置为 12。
- 队列容量:可以设置较大的队列容量,因为 I/O 密集型任务处理时间相对较长,新任务到来的频率相对稳定,较大的队列可以缓存更多任务,减少创建新线程的频率,降低上下文切换开销。例如可以设置为几百甚至更大,具体数值需要根据实际任务处理速度和任务到达频率来调整。
- CPU密集型任务
- 核心线程数:CPU 密集型任务几乎一直在使用 CPU 资源,过多的线程并不会提高性能,反而会增加上下文切换的开销。因此,核心线程数一般设置为 CPU 核心数,或者 CPU 核心数 + 1。例如 CPU 是 4 核,核心线程数设置为 4 或 5。这样能保证在充分利用 CPU 资源的同时,尽量减少上下文切换带来的性能损耗。
- 最大线程数:与核心线程数相同或稍大一点即可。由于 CPU 资源已经被充分利用,过多线程只会降低性能,所以最大线程数不宜比核心线程数大太多。例如核心线程数为 4,最大线程数可设置为 5。
- 队列容量:设置较小的队列容量,因为 CPU 密集型任务处理速度相对较快,任务队列不会长时间堆积任务。较小的队列容量可以使线程池更快地创建新线程来处理任务,避免任务在队列中长时间等待。例如可以设置为几十,具体数值可根据实际情况调整。