写在前面
本文是我自己对ThreadPoolExecutor的简单理解,是看了ThreadPoolExecutor的源码和orcle官网的文档之后的体会,并不是一板一眼的翻译官网,也建议大家结合学习。
如果有误,欢迎大家批评指正哈~
官网网址
Java™ Platform Standard Ed. 8 Class ThreadPoolExecutor
线程池ThreadPoolExecutor解决的问题:
提高大量同步任务的执行性能;
维护一些基本的数据,比如已完成的任务数
参数:
1.corePoolSize & maximumPoolSize
- 当前线程数少于cirePoolSize,一定会开新的线程。
- 当前线程数大于corePoolSize,少于maximumOiikSuze,只有在队列曼联的时候才会开新的线程。
- 一般是构建的时候初始化,但是可以通过set方法动态更改。
2.预先启动核心线程池的方法
prestartAllCoreThreads(),prestartAllCoreThreads()
3.生存时间
若当前线程数超过了核心线程池的线程数,多余的线程会被terminated掉
4.队列
任何类,只要实现了BlockingQueue接口,就能被用来传输和持有提交的任务。该队列与线程池的规模有关:
- 如果当前运行的线程数<corePoolSize,线程被创建,不放入队列
- 如果当前运行的线程数>=corePoolSize,线程被放入队列
- 如果当前运行加入会使得总线程数>maximumPoolSize,任务被拒绝
实现了BlockingQueue的类
( 注意:根据阿里编程规范:不建议用Executors.newFixedThreadPool()、Executors.newCachedThreadPool()和Executors.newSingleThreadExecutor(),建议new ThreadPoolExecutor(…),因为Executors的几个方法都是对ThreadPoolExecutor进行了封装,一个好的程序员应该了解其底层实现呦):
1. SynchronousQueue:
- 该队列不保留任何任务,统统直接扔给线程。要是线程池的线程个数超maximumPoolSize了,就拒绝任务。
- Executors.newCachedThreadPool()就用的这个。所以java编程思想p657里会说:newCachedThreadPool通常会创建与所需数量相同的线程。在newCachedThreadPool的实现中,maximumPoolSize=Interger.MAX_VALUE,可以看成允许创建无限长的线程啦
- Executors.newCachedThreadPool()缺点是:当提交的任务过多的时候,会创建大量的线程,导致OOM/
2. LinkedBlockingQueue:
- 如果不预定义容量,该队列会建立一个无限长的队列(其实长度是Interger.MAX_VALUE,可以看成无限长啦)。
- 任务什么情况下会被放入队列里呢?当运行的任务数>corePoolSize时,就会被放入。而因为这个队列是无限长的,所以maximumPoolSize属性不起任何作用了。
- 所以我们看一下newFixedThreadPool的实现:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
- Executors.newFixedThreadPool()和Executors.newSingleThreadExecutor()就用的这个,适用于类似网页访问这种,访问量可能大到无法估计的情况。使用该方法定义的线程池,运行的线程数是固定的。
3. ArrayBlockingQueue:
看不下去了