携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第11天,点击查看活动详情
手动创建线程有两个缺点:
- 创建线程过多导致内存资源耗尽
- 线程频繁创建销毁开销大
创建线程池
建议使用 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
直接丢弃提交的任务