为什么要使用线程池

184 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第11天,点击查看活动详情


手动创建线程有两个缺点:

  1. 创建线程过多导致内存资源耗尽
  2. 线程频繁创建销毁开销大

创建线程池

建议使用 ThreadPoolExecutor 创建线程池,其中涉及7个参数

核心线程数 corePoolSize

核心线程数就是常驻在线程池中不会被销毁的线程数量,默认为1,自定义时可以如下推算

假设每个任务允许的最大响应时间为0.2s,每个任务实际处理时间为0.05s,那么在0.2s内每个线程可以处理5个任务,如果0.2s内请求的任务数为20个,那么核心线程数就为20/5=4个。

核心线程是否销毁需要根据 allowCoreThreadTimeout 决定,若设置为true,那么也会超时销毁,可以视为 corePoolSize=0

最大线程数 maximumPoolSize

当核心线程都被占用,且任务队列已满时,如果又有新任务加入,那么

  • 如果当前线程数小于maximumPoolSize,线程池创建新线程运行任务
  • 如果当前线程数大于maximumPoolSize,使用拒绝策略

线程空闲时间 keepAliveTime、timeUnit

用于判断是否要销毁空闲线程的参数,如果池中的线程数量大于corePoolSize,那么如果线程的空闲时间超过 keepAliveTime 时,就会被销毁,直到线程数量等于corePoolSize。

任务队列 workQueue

当核心线程都被占用,新提交的任务首先加入任务队列,等待被线程池消耗。

SynchronousQueue

一个不存储元素的队列,当新任务提交后马上被抛出,由最大线程数决定后续操作。Executors.newCachedThreadPool() 使用了这种类型的队列。

LinkedBlockingQueue

链表构成的最大长度为 Integer.MAX_VALUE 的队列,可认为是无限队列,最大线程数不生效。

ArrayBlockingQueue

一个底层为数组构成的有界队列,整个线程池中最大的线程数量为maximumPoolSize

线程工厂 ThreadFactory

用来生成线程的工厂

拒绝策略 RejectedExecutionHandler

当池中的线程的数量超过了最大线程数,需要使用拒绝策略处理新提交的任务

AbortPolicy

默认的拒绝策略,抛出异常来拒绝

CallerRunsPolicy

让提交任务的线程自己之心该任务

DiscardOldestPolicy

丢弃任务队列中最早加入的任务,将新任务放到任务队列

DiscardPolicy

直接丢弃提交的任务