好久没有写博客了,今天来写一个线程池的内容。
我们先来看一个简单地例子:
ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(5);
executor.execute(new Running(1));
这段代码就是我们在使用线程池的时候最基本的一个使用方式了,而这里出现的几个类,ThreadPoolExecutor、Executors等,究竟分别是干什么用的呢?本着面向对象的原则,我们有必要去了解一下整个线程池的类族设计。
一.类族设计
为了方便起见,在了解类族结构的时候,我们不直接读源码,采用阅读jdk api的方式,首先在源码中不断寻找父类和接口后,我们发现,其最高位的祖先为Executor接口,查看接口api,其解释如下:
这个接口的设计原则,顾名思义,就是Runnable的执行器,接口的设计者认为我们不应该使用new Thread。。。的方式去启动一个线程,而是采用Executor的实现类去启动,至于其原因,我相信对于那些对面向对象思想有一定理解的童鞋一定不会觉得难以理解,这种将线程的启动方式隐藏在实现类内部的设计,不但可以让线程的生命周期的处理变得统一,且对于不同处理方式的线程也可以分门别类,更重要的是,他可以让线程的启动和线程的执行业务完成抽象分离,交由不同的开发者去处理,这也就是为什么jdk(或者其他第三方库)设计的线程池(或者其他线程执行类)能够简单地用于我们自己开发的业务的线程的实际执行。
再来看Executor的子接口ExecutorService:
这里说明了两个问题:1.Service提供了管理终止的方法;2.Executors提供了关于这个接口的工厂方法。
第二点很好理解,我们在开头的例程中使用Executors去创建一个ThreadPoolExecutor,这就很明显是一个工程类了。
而第一点,官方也给出例程来解释:
class NetworkService implements Runnable {
private final ServerSocket serverSocket;
private final ExecutorService pool;
public NetworkService(int port, int poolSize)
throws IOException {
serverSocket = new ServerSocket(port);
pool = Executors.newFixedThreadPool(poolSize);
}
public void run() { // run the service
try {
for (;;) {
pool.execute(new Handler(serverSocket.accept()));
}
} catch (IOException ex) {
pool.shutdown();
}
}
}
class Handler implements Runnable {
private final Socket socket;
Handler(Socket socket) { this.socket = socket; }
public void run() {
// read and service request on socket
}
}
在这个例程中,对于execute操作发生异常的情况下,强制使用shutdown来关闭线程。
另外虽然官方文档没有强调,但是在ExecutorService中还设计了一系列面向Callable接口的方法。关于Callable和Runnable的区别,我们以后有机会再说。
继续看其实现类,一个抽象类AbstractExecutorService
这个类实现了一些基本的方法,但是并不实现具体的线程启动操作。
最后就是我们本次博客的主角,ThreadPoolExecutor了。
到目前为止,类族的结构应该已经看得比较清晰了,我们就来具体看一下,ThreadPoolExecutor的类结构吧。
二.ThreadPoolExecutor构造方法
这个类的构造方法比较多,由于不同的构造方法之间都是互相调用来调用去的,我们直接看参数最多的那个构造函数就可以啦。
看官方参数解释:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
corePoolSize
- 池中所保存的线程数,包括空闲线程。
maximumPoolSize
- 池中允许的最大线程数。