# 线程池的构造函数

我们经常使用线程池的构造函数来创建线程池

线程池的构造函数常见参数如下

参数名 类型 含义
corePoolSize int 核心线程数
maxPoolSize int 最大线程数
keepAliveTime long 保持存活时间
workQueue BlockingQueue 任务存储队列
threadFactory ThreadFactory 当线程池需要新的线程的时候,会使用ThreadFactory来生成新的线程
Handler RejectedExecutionHandler 由于线程池无法接受你所提交的任务的拒绝策略

# corePoolSize 和 maxPoolSize

corePoolSize 指的是核心线程数:线程池在完成初始化后,默认情况下,线程池中并没有任何线程,线程池会等待有任务来时,再创建新的任务去执行任务。

maxPoolSize :线程池有可能会在 corePoolSize 的基础之上,额外增加一些线程,但是这些增加的线程数是有一个上限的,这个上限就是maxPoolSize

corePoolSize 和 maxPoolSize

# keepAliveTime

如果线程池当前的线程数多于 corePoolSize ,那么如果多余的线程 空闲时间 超过 keepAliveTime ,他们就会被终止。

# workQueue

任务存储队列

三种常见的队列:

类型 描述
SynchronousQueue 直接交接队列 任务不多常用的队列
LinkedBlockingQueue 无界队列 任务处理速度必须大于提交速度
ArrayBlockingQueue 有界队列 可以设置队列大小

# ThreadFactory

新的线程是由 ThreadFactory 创建的,默认使用 Executors.defaultThreadFactory() ,创建出来的线程都在同一个线程组,拥有同样的NORM_PRIORITY优先级并且都不是守护线程。 如果自己指定 ThreadFactory ,那么就可以改变线程名、线程组、优先级、是否是守护线程等。

# 添加线程的规则

  1. 如果线程数小于 corePoolSize ,即使其他工作线程处于空闲状态,也会创建一个线程来执行新的任务
  2. 如果线程数等于(或大于)corePoolSize ,但小于 maxPoolSize ,则将任务放入队列。
  3. 如果队列已满,并且线程数小于 maxPoolSize ,此时就会创建一个新的线程来运行任务。
  4. 如果队列已满,并且线程数大于或等于 maxPoolSize ,则拒绝该任务。

判断顺序: corePoolSize、 workQueue、 maxPoolSize

线程池添加线程流程图

# 增减线程的特点

  1. 通过设置 corePoolSizemaximumPoolSize 相同,就可以创建固定大小的线程池。
  2. 线程池希望保持较少的线程数,并且只有在负载变得很大时才增加它。
  3. 通过设置 maximumPoolSize 为很高的值,例如 Integer.MAX_VALUE ,可以允许线程池容纳任意数量的并发任务。
  4. 是只有在队列填满时才创建多于 corePoolSize 的线程,所以如果你使用的是无界队列(例如 LinkedBlockingQueue ),那么线程数就不会超过 corePoolSize

# 线程池应该手动创建还是自动创建?

手动创建更好,因为这样可以让我们更加明确线程池的运行规则,避免资源耗尽的风险。

自动创建线程池(也就是直接调用JDK封装好的构造函数)可能带来OOM异常。

常见的四种自动创建线程池的方式

类型 描述 特点
newFixedThreadPool 固定线程池 corePoolSize 和 maxPoolSize 一样大的无界线程池
newSingleThreadExecutor 单线程线程池 corePoolSize 和 maxPoolSize 都是1的无界线程池
newCachedThreadPool 可缓存线程池 corePoolSize是1 maxPoolSize是Integer.MAX_VALUE的无界线程池,具有自动回收多余线程的功能
newScheduledThreadPool 周期线程池 支持定时周期性执行的线程池

# 线程池里的线程数量设定为多少比较合适?

  • CPU密集型(加密、计算hash等):最佳线程数为CPU核心数的1-2倍左右。
  • 耗时IO型(读写数据库、文件、网络读写等):最佳线程数一般会大于cpu核心数很多倍(比如10倍),以JVM线程监控显示繁忙情况为依据,保证线程空闲可以衔接上。
  • 可以参考Brain Goetz推荐的计算方法:线程数 = CPU核心数 *( 1 + 平均等待时间 / 平均工作时间 )