8

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

 9 months ago
source link: https://nicksxs.me/2023/11/05/Tomcat-%E7%B3%BB%E5%88%97%E7%AF%87%E5%85%AB-%E4%BB%8B%E7%BB%8D%E4%B8%8B-Tomcat-%E9%87%8C%E7%9A%84%E7%BA%BF%E7%A8%8B%E6%B1%A0%E7%94%A8%E5%A4%84/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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

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

@Override
    protected void initInternal() throws LifecycleException {
        reconfigureStartStopExecutor(getStartStopThreads());
        super.initInternal();
    }

这里先会获取线程数,

@Override
public int getStartStopThreads() {
    return startStopThreads;
}

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

private int startStopThreads = 1;

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

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 开始方法中,

// 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 也比较简单

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

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);
}

然后进行执行,

@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 的,后面可以再继续介绍下


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK