Tomcat 系列篇八-介绍下 Tomcat 里的线程池用处

线程池在 Tomcat 中也是非常重要的工具,这里我们简单介绍下 Tomcat 中的线程池,在 container 的启动过程中
org.apache.catalina.core.ContainerBase#initInternal

1
2
3
4
5
@Override
protected void initInternal() throws LifecycleException {
reconfigureStartStopExecutor(getStartStopThreads());
super.initInternal();
}

这里先会获取线程数,

1
2
3
4
@Override
public int getStartStopThreads() {
return startStopThreads;
}

默认的 ContainerBase 的设置线程数是 1

1
private int startStopThreads = 1;

那就会按照 org.apache.catalina.core.ContainerBase#reconfigureStartStopExecutor 来设置线程池类型

1
2
3
4
5
6
7
8
9
10
11
12
13
private void reconfigureStartStopExecutor(int threads) {
if (threads == 1) {
// Use a fake executor
if (!(startStopExecutor instanceof InlineExecutorService)) {
startStopExecutor = new InlineExecutorService();
}
} else {
// Delegate utility execution to the Service
Server server = Container.getService(this).getServer();
server.setUtilityThreads(threads);
startStopExecutor = server.getUtilityExecutor();
}
}

此时线程池类型是 null 也就会走到上一个分支中,new 一个 InlineExecutorService 出来
前面的这些其实是在 StandardEngine 初始化过程中,也就是 initInternal 时候进行的
然后具体的使用是在 startInternal 开始方法中,

1
2
3
4
5
6
// Start our child containers, if any
Container children[] = findChildren();
List<Future<Void>> results = new ArrayList<>();
for (Container child : children) {
results.add(startStopExecutor.submit(new StartChild(child)));
}

会获取当前 StandardEngine 的子组件提交给线程池进行启动
而这个 StartChild 也比较简单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private static class StartChild implements Callable<Void> {

private Container child;

public StartChild(Container child) {
this.child = child;
}

@Override
public Void call() throws LifecycleException {
child.start();
return null;
}
}

就是调用子组件的 start 方法,
在 org.apache.tomcat.util.threads.InlineExecutorService 的父类,java.util.concurrent.AbstractExecutorService 中先会把 Callable 包装成 FutureTask

1
2
3
4
5
6
7
8
9
public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
return new FutureTask<T>(callable);
}

然后进行执行,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Override
public void execute(Runnable command) {
synchronized (lock) {
if (shutdown) {
throw new RejectedExecutionException();
}
taskRunning = true;
}
command.run();
synchronized (lock) {
taskRunning = false;
if (shutdown) {
terminated = true;
lock.notifyAll();
}
}
}

这个就是我们 startStopExecutor 的主要作用,帮我们启动子组件
对于 Container 来说启动的就是 host,而其实 host 也是继承了 ContainerBase 的,后面可以再继续介绍下