写点什么

ThreadPoolExecutor 线程池使用

发布于: 2020 年 07 月 03 日

开发规范



阿里巴巴开发规范中指出了3点和线程使用相关的强制措施。



1、创建线程或线程池时请指定有意义的线程名称,方便出错时回溯。

2、线程资源必须通过线程池提供,不允许在应用中自行显式创建线程。

3、线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。



不允许使用 Executors 创建的原因如下。

1)FixedThreadPool 和 SingleThreadPool:

允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。

2)CachedThreadPool 和 ScheduledThreadPool:

允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。

手动创建线程池的方法



ThreadPoolExecutor 提供了几个构造方法,拿参数最全的举例说明。



public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)



参数意义



  • corePoolSize,核心线程数,即便线程空闲也会存活的数量

  • maximumPoolSize, 最大线程数,允许创建线程的最大数量

  • keepAliveTime,超过核心线程数时,空闲线程等待 keepAliveTime 时间后才进行回收

  • unit,keepAliveTime 的时间单位

  • workQueue, 任务执行前所保存到的队列,可自定义长度,FixedThreadPoolSingleThreadPool 使用的是LinkedBlockingQueue,默认最大长度是 Integer.MAX_VALUE

  • threadFactory,创建线程的工厂,可以使用 guava 的 new ThreadFactoryBuilder().setNameFormat("我的线程-task-%d").build() 来创建一个自定义名称的线程工厂

  • handler,拒绝策略的实现,当线程池异常关闭或者任务队列满时,再次提交任务则会执行拒绝策略

  • AbortPolicy,默认的策略,抛出异常

  • DiscardPolicy,直接丢弃

  • DiscardOldestPolicy,丢弃队列中最老的任务,然后尝试执行()

  • CallerRunsPolicy,由调用线程执行此任务



其它构造方法



最少参数的构造方法使用默认线程工厂和默认拒绝策略。



public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}



线程的创建过程



使用线程池的 execute(Runnable command) 方法提交任务。



  • 如果当前线程数小于corePoolSize,则创建新的线程

  • 如果当前线程数大于等于 corePoolSize,则加入到工作队列workQueue中,当队列已满,则创建新的线程

  • 线程数达到 maximumPoolSize,且队列满时,将执行拒绝策略



思考



在有大量任务执行的场景,如果使用不恰当的创建线程池的方式,可能会引起线上的问题,例如 OOM。所以阿里强制程序员使用自定义线程池,创建线程池时清楚地指定好各个参数,避免深度的封装类导致不知道实现细节而踩坑。



发布于: 2020 年 07 月 03 日阅读数: 113
用户头像

后端开发,30岁的郭儿的跋涉。 2018.07.04 加入

http://www.ruiyan.run,公众号:郭儿的跋涉

评论

发布
暂无评论
ThreadPoolExecutor 线程池使用