为什么使用线程池

线程池可以看做是线程的集合。在没有任务时线程处于空闲状态,当请求到来:线程池给这个请求分配一个空闲的线程,任务完成后回到线程池中等待下次任务(而不是销毁)。这样就实现了线程的重用。
如果没有使用线程池,就需要为每个请求都新开一个线程,虽然可以,但是有缺点:

  • 线程生命周期的开销非常高。每个线程都有自己的生命周期,创建和销毁线程所花费的时间和资源可能比处理客户端的任务花费的时间和资源更多,并且还会有某些空闲线程也会占用资源。
  • 程序的稳定性和健壮性会下降,每个请求开一个线程。如果受到了恶意攻击或者请求过多(内存不足),程序很容易就奔溃掉了。
常使用的线程池为ThreadPoolExecutor
  • 使用Executors工厂方法配置
  • 使用核心线程数量和最大线程数量;如果运行的线程数量少于corePoolSize,则创建新线程来处理请求,即使其它辅助线程是空闲的;如果运行线程大于corePoolSize,小于maximumPoolSize,则仅当队列满时才创建新线程;若两者设置相同,创建固定大小的线程池;若设置了maximumPoolSize为最大值max_value,允许任意数量的并发任务
  • 默认只有当任务请求过来,才会初始化核心线程,可以使用方法重写
  • 新创建的线程属于同一个线程组,相同优先级,没有守护线程
  • 线程数大于核心线程,线程空闲时间大于keepalivetime,会销毁
  • 排队策略:同步移交,直接移交至线程,若没有执行线程则新建它,用于线程池无限制;无限制策略,队列等待;有界限策略避免资源耗尽
内部状态

变量ctl定义为原子整型,记录线程池中任务数量和线程池状态两个信息
线程状态
RUNNING:线程池能够接受新任务,以及对新添加的任务进行处理。

SHUTDOWN:线程池不可以接受新任务,但是可以对已添加的任务进行处理。

STOP:线程池不接收新任务,不处理已添加的任务,并且会中断正在处理的任务。

TIDYING:当所有的任务已终止,ctl记录的"任务数量"为0,线程池会变为TIDYING状态。当线程池变为TIDYING状态时,会执行钩子函数terminated()。terminated()在ThreadPoolExecutor类中是空的,若用户想在线程池变为TIDYING时,进行相应的处理;可以通过重载terminated()函数来实现。

TERMINATED:线程池彻底终止的状态。