线程池是日常开发中常用的技术,使用也非常简单,不过想使用好线程池也不是件容易的事,开发者需要不断探索底层的实现原理,才能在不同的场景中选择合适的策略,最大程度发挥线程池的作用以及避免踩坑。
一、线程池工作流程
以下是 Java 线程池的工作流程,涉及创建线程的参数及拒绝策略,如果读者对这部分内容不太了解,可参考其他的文档,本文不在赘述。
Java 里面线程池的顶级接口是 Executor,但是严格意义上讲 Executor 并不是一个线程池,而只是一个执行线程的工具。
真正的线程池接口是 ExecutorService。下面这张图完整描述了线程池的类体系结构。
Executor 是一个顶层接口(类似一个标记接口),在它里面只声明了一个方法 execute (Runnable),返回值为 void,参数为 Runnable 类型,从字面意思可以理解,就是用来执行传进去的任务的;
然后 ExecutorService 接口继承了 Executor 接口,并声明了一些方法:submit、invokeAll、invokeAny 以及 shutDown 等;
抽象类 AbstractExecutorService 实现了 ExecutorService 接口,基本实现了 ExecutorService 中声明的所有方法;
ThreadPoolExecutor 继承了类 AbstractExecutorService。
整理得:
二、线程池进阶
1、线程池的创建
需要手动通过 ThreadPoolExecutor 创建,使用者要非常明确业务场景并定制线程池,避免误用可能导致的问题。
以下是阿里巴巴 Java 开发手册中的描述:
ThreadFactory:推荐使用 guava 中的 ThreadFactoryBuilder 创建:
new ThreadFactoryBuilder().setNameFormat("name-%d").build();
复制代码