189 8069 5689

Java线程池ThreadPoolExecutor-创新互联

前言

多线程一直是Java进阶的必修课。在Java中,我们很早就知道可以通过 Thread 类和 Runnable 接口来实现多线程。与之有着类似职责的数据库连接,也可通过JDBC创建与使用。但我们深知无论是数据库连接的创建与销毁,还是线程的创建与销毁,都是一件及其消耗性能的事情。为了减少这种情况的发生,前辈们就在思考,是不是可以复用已有的数据库连接?减少创建,销毁动作?这就是后来数据库连接池的由来。同样的,为了复用线程,也就有了线程池。我一直独自暗喜,身为一位幸福的Java程序员,前有Java虚拟机管理内存,后有Doug Lea 大师提供并发库,锁机制。简直幸福的不像话,不过幸福归幸福,该掌握的还是需要掌握的,我们一起来看看今天的主角:ThreadPoolExecutor。

创新互联是创新、创意、研发型一体的综合型网站建设公司,自成立以来公司不断探索创新,始终坚持为客户提供满意周到的服务,在本地打下了良好的口碑,在过去的十多年时间我们累计服务了上千家以及全国政企客户,如成都广告设计等企业单位,完善的项目管理流程,严格把控项目进度与质量监控加上过硬的技术实力获得客户的一致表扬。
简介

在面试过程中,也时常会遇到一些关于线程池的问题,例如:

  1. 线程池中核心参数有哪些?

  2. 有没有自己实现过线程池?

  3. 如果让你自己实现线程池,你会怎么做?

这些问题,其实考核的就是Java线程池的知识,更具体一点就是对ThreadPoolExector类熟不熟悉,下面代码是ThreadPoolExector类的全参构造函数。下面我们就一一对参数进行了解。

public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
 if (corePoolSize < 0 ||
 maximumPoolSize <= 0 ||
 maximumPoolSize < corePoolSize ||
 keepAliveTime < 0)
 throw new IllegalArgumentException();
 if (workQueue == null || threadFactory == null || handler == null)
 throw new NullPointerException();
 this.corePoolSize = corePoolSize;
 this.maximumPoolSize = maximumPoolSize;
 this.workQueue = workQueue;
 this.keepAliveTime = unit.toNanos(keepAliveTime);
 this.threadFactory = threadFactory;
 this.handler = handler;
 }

其中:

  1. corePoolSize:表示该线程池最小的工作线程数。默认情况下,当需要使用时创建线程,也可以调用 prestartAllCoreThreads() 方法进行预创建所有的核心线程。

  2. maximumPoolSize:表示该线程池大的线程数量,理论上将其设置为无限大,就会创建无限多的线程,当然,创建线程的数量最终由系统资源也就是操作系统决定。

  3. keepAliveTime:表示空闲线程的超时时间,(单位为纳秒)。但在构造函数中,单位与unit 参数配合使用,最终转换为纳秒。

  4. unit:表示空闲线程超时的时间单位,可选值有:java.util.concurrent.TimeUnit中的值,SECONDS(秒),MINUTES(分),HOURS(小时),DAYS(天) 等。

  5. workQueue :表示工作队列(其实是一个runnable队列,在线程池中定义为Worker),其基类为:java.util.concurrent.BlockingQueue。

  6. threadFactory:线程工厂,通常用于创建线程,以及命令规则。默认为: Executors.defaultThreadFactory()。

  7. handler 表示处理策略,当workQueue队列满时,以及创建线程错误时的处理策略。其基类为 java.util.concurrent.RejectedExecutionHandler。默认为:AbortPolicy 策略。

不同组合

在 java.util.concurrent.Executors类为我们提供了多种组合,其底层还是调用ThreadPoolExecutor。下面列举几个常用的方法:

1. newFixedThreadPool

public static ExecutorService newFixedThreadPool(int nThreads) {
  return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue());
}
...

特性:线程数量大小固定,且 corePoolSize 与 maximumPoolSize 数量相等。当线程数量设置太少时。task则会积压在LinkedBlockingQueue队列中。当 task 任务大于Integer.MAX_VALUE时 则会有OOM发生的风与之类是的还有newSingleThreadExecutor方法。

2. newCachedThreadPool

public static ExecutorService newCachedThreadPool() {
  return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue());
}

特性:corePoolSize数量为0,maximumPoolSize数量为Integer.MAX_VALUE,也就是说理论上是可以创建Integer.MAX_VALUE个线程的。keepAiveTime时间为 60秒。BlockingQueue使用的是SynchronousQueue,由于其没用容量,意味这每一次put对应着一次take操作,其吞吐量比较高。正因为如此,当task到达一定程度时,可能会创建许多线程,从而导致OOM,甚至服务不可用。

上述方法其实是对ThreadPoolExecutor方法的封装对不对,知道了ThreadPoolExecutor的每一个参数,再来使用这个,就得心应手了对不对。

规范

Executors类这么方便,是不是可以直接使用Executors类来创建呢?当然可以,但并不建议这样做。在《阿里Java手册》中的并发处理小节中有提到:

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

说明:Executors 返回的线程池对象的弊端如下:
1) FixedThreadPool 和 SingleThreadPool :
允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM 。
2) CachedThreadPool 和 ScheduledThreadPool :允许的创建线程数量为 Integer.MAX_VALUE ,可能会创建大量的线程,从而导致 OOM 。

在实际应用中,我们应该遵守规范,避免掉一些没必要的问题。该规约其最终目的是让大家能够更清楚了解线程池的每个参数,从而达到能够在实际应用场景中调为最优组合使用,使其达到大性能。同样的,我们也通过安装阿里巴巴的规约插件进行自动扫描与提醒。在Idea中 File -> Setings -> Plugins -> Browse repositories中搜索『Alibaba Java Coding Guidelines』安装即可!

小结

在这篇文章中,算是对ThreadPoolExector的一个初步了解。知道了其核心参数,到底是怎么回事。但这还并不够,且不足以学以致用,还有很多疑问,如:

  1. ThreadPoolExecutor的原理是怎样的?

  2. 我们如何自定义一个线程池?

  3. ThreadPoolExecutor在Dubbo中的实践

这些疑惑都需要一一去揭晓。由于篇幅原因,这些会作为好几篇文章进行记录。其目的是能够学以致用,面试时也能得心应手。


相关阅读:

《使用 Mybatis 真心不要偷懒!》

《再谈Java 生产神器 BTrace》

《Java 生产神器  BTrace》

《重构不完全指南!》


如果想深入学习Java并发编程,下面这本书是值得阅读的。当然了,如果你读喜欢电子书,也可以回复公众号消息『Java并发编程的艺术』进行免费获取!

Java线程池ThreadPoolExecutor

创新互联www.cdcxhl.cn,专业提供香港、美国云服务器,动态BGP最优骨干路由自动选择,持续稳定高效的网络助力业务部署。公司持有工信部办法的idc、isp许可证, 机房独有T级流量清洗系统配攻击溯源,准确进行流量调度,确保服务器高可用性。佳节活动现已开启,新人活动云服务器买多久送多久。


网页名称:Java线程池ThreadPoolExecutor-创新互联
网站链接:http://cdxtjz.cn/article/eepcc.html

其他资讯