简单介绍
ThreadPoolExecutor
就是大家常说的线程池, 顾名思义它就是一个池子, 里面有一批称为线程的东西 ,使用者向线程池提交任务, 不用关心是那个线程执行了任务(不关心其底层实现), 只要关心任务是否正常结束即可, 甚至都可以不关心任务是否正常结束, 只管提交. 并且使用者提交完任务之后, 其可以解放出来去做其他的工作, 如果使用者关心任务的状态或者结果, 则可以选择对应的提交任务方式.
基本使用
基于上述线程池的简单介绍, 可以得出ThreadPoolExecutor
主要提供两种能力
- 线程缓存: 执行大量异步任务时通过缓存一定数量的线程减少线程切换,提供更好的性能.
- 资源管理: 当执行任务时, 提供有限的资源供执行任务使用, 并且提供基本的统计结果.
使用ThreadPoolExecutor
, 需要了解它的几个构造器. 它的构造器如下图. 手动构建线程池最小需要写5个参数, 最多要写7个.
上图中, 从上到下共4个构造器, 前三个构造器都最终调用了第四个构造器. 第四个构造器共有7个参数, 从左到右, 在下面表格中分别介绍7个参数.
参数 | 类型 | 参数含义 |
---|---|---|
corePoolSize | int | 当提交任务时, 如果发现当前运行的线程数小于corePoolSize, 则会新创建线程去处理该任务, 并且当其他新建的线程闲置时也会创建线程 |
maximumPoolSize | int | 当线程数量大于corePoolSize的配置, 同时队列任务放满了, 则会创建新的线程处理,但是创建之后的线程总数量并不能大于maximumPoolSize配置的 |
keepAliveTime | long | 当大于corePoolSize的线程闲置时间大于配置时间, 则会被终止 |
unit | TimeUnit | keepAlieTime的时间单位, TimeUnit.SECONDS, TimeUnit.HOURS |
workQueue | BlockingQueue | 没有运行的任务将会保存在该队列中, 当开始运行则会移除 |
threadFactory | ThreadFactory | 提供线程, 该参数有默认值 |
handler | RejectExecutionHandler | 拒绝策略, 这里的拒绝并不是不执行, 该参数有默认值(AbortPolicy, 抛出异常) |
只看上面的文字有点难以理解, 下面通过新建一个简单的线程池来了解一下.
// corePoolSize = 5
// maximumPoolSize = 10
// keepAliveTime = 3L
// unit = TimeUnit.SECOND
// workQueue = LinkedBlockingQueue(10)
// threadFactory 采用默认值
// handler 采用默认值
ExecutorService executorService =
new ThreadPoolExecutor(5, 10, 3L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(10));
上面创建的线程池最多能同时存在20个任务, 其中10个是运行的, 而剩余的10个存储在阻塞链表中. 当两者全部满了(有20个任务), 再提交任务会被拒绝(前面提到的默认handler
,抛出异常), 需要注意10个运行的线程并不是提交10个任务立马就会启动10个线程, 而是先启动5个, 因为corePoolSize
等于5, 其余的任务放到阻塞链表中, 若阻塞链表中存放的任务溢出, 才会启动新的线程, 启动的线程总数受maximumPoolSize
限制, 并且启动的线程数量超过corePoolSize
的限制之后, 超过的线程受配置最长闲置时间的影响, 若超时还未有任务产生, 则线程会退出.
基于上面创建的线程池,来看下常用的API.
最基本的提交任务API是execute
, 它接受一个对象, 对象必须实现Runnable
接口. 提交任务之后, 任务则会在未来某个时间执行. 这里需要注意, 该方法是没有返回值的. void execute(Runnable)
方法是Executor
接口中定义的, 它也是Executor
唯一的方法.
void executorService.executor(Runnable);
下面是使用submit
进行进行, 它是一类方法, 提供更强大的适配性.
// submit提交方式(一)
// 用Future封装了call方法的返回值.
Future<String> result = executorService.submit(new Callable<String> {
@Override
public String call() throws Exception {
return "hello, world";
}
});
// submit提交方式(二)
// 如果任务结束, 则Future中封装的是null.
Future<?> result = executorService.submit(new Runnable() {
@Override
public void run() {
return;
}
});
// submit提交方式(三)
// 当任务结束之后, 返回传入的结果, 这里是"SUCCESS"
// 任务结束之后: result.get() 返回 "SUCCESS"
Future<String> result = executorService.submit(new Runnable() {
@Override