线程池ThreadPoolExecutor

#面试 #java

1. 核心参数有哪些?


2. 工作原理是什么?

  1. 刚开始:线程池里没有线程,来一个任务就创建一个 worker 线程去处理,直到达到 corePoolSize
  2. 超过核心线程数:新任务就扔到队列里。队列满了,就尝试继续创建线程(不超过 maxSize)
    • 小技巧:把 corePoolSize 和 maxCorePoolSize 设成一样,这样就优先创建线程,再用队列
  3. 队列清空后:如果线程数大于 coreSize,就开始清理多余的线程。判断 keepAliveTime 到了没,到了就销毁,始终保持 corePoolSize
  4. 有界队列满了:触发拒绝策略 RejectedExectionHandler
  5. 无界队列:内存会一直涨,最后可能 OOM

jdk线程池原理.png


3. 要注意什么?

3.1 JDK 线程池适合 CPU 密集型任务

JDK 的线程池会优先把任务扔队列,而不是创建更多线程。为什么这么设计?

因为 CPU 密集型任务(大量计算)会让 CPU 很忙,这时候线程数和 CPU 核数差不多就够了。线程太多反而会频繁切换上下文,降低效率。所以超过核心线程数后,线程池不会马上加线程,而是让任务在队列里等核心线程空闲。

Tomcat 使用的线程池就不是 JDK 原生的线程池,而是做了一些改造,当线程数超过 coreThreadCount 之后会优先创建线程,直到线程数到达maxThreadCount,这样就比较适合于 Web 系统大量 IO 操作的场景了。

3.2 队列堆积要监控

队列堆积量是个重要指标,特别是对实时性要求高的任务。堆积太多说明处理不过来了。

3.3 别用无界队列

用线程池一定记住:别用无界队列(没设大小限制的队列),不然内存会被撑爆。