关于springboot访问tomcat,线程http-nio-8080-exec的来源问题

2年前 (2022) 程序员胖胖胖虎阿
362 0 0

最近在看并发操作时候,例如jmeter进行接口压测(本地自己的springboot2的环境),发现一个有趣的现象,就是关于线程http-nio-8080-exec-1,http-nio-8080-exec-2等等的出现。但是这个线程数不管我的压测数是多少这个线程数不会超过10.抱着好奇的心去搜索了一下相关的文章,但是没有看到比较合适的。然后就只有自己去跟了一下源码。在此自己总结一下。

两个问题:

1、这个http-nio-8080-exec东西是怎么来的
2、为什么这个线程数不超过10

把这两个问题其实可以一起归为一个问题来跟代码进行解决:
因为我们知道,一般在自定义线程或者线程池名称的时候,我们是可以自己去设置相关的线程名字的。这个名称的来源就是如下:

在请求线程经过Tomcat时,会进入到org.apache.coyote.AbstractProtocol,这个方法,这是一个抽象类,可以看出其实这里就是在进行一个名称和端口号的拼接操作。getNamePrefix()的具体实现是在org.apache.coyote.http11.Http11NioProtocol

private String getNameInternal() {
        StringBuilder name = new StringBuilder(getNamePrefix());
        name.append('-');
        if (getAddress() != null) {
            name.append(getAddress().getHostAddress());
            name.append('-');
        }
        int port = getPortWithOffset();
        if (port == 0) {
            // Auto binding is in use. Check if port is known
            name.append("auto-");
            name.append(getNameIndex());
            port = getLocalPort();
            if (port != -1) {
                name.append('-');
                name.append(port);
            }
        } else {
            name.append(port);
        }
        return name.toString();
    }
@Override
    protected String getNamePrefix() {
        if (isSSLEnabled()) {
            return "https-" + getSslImplementationShortName()+ "-nio";
        } else {
            return "http-nio";
        }
    }

 当创建连接的时候回进入到org.apache.tomcat.util.net.AbstractEndpoint,进入start()方法
 

 public final void start() throws Exception {
        if (bindState == BindState.UNBOUND) {
            bindWithCleanup();
            bindState = BindState.BOUND_ON_START;
        }
        startInternal();
    }

 然后是startInternal(),在这个方法有一段

if (getExecutor() == null) {
    createExecutor();
}。也就是说,如果这个是一个新连接的话,会去新建一个线程。createExecutor()这个方法很重要算是核心实现了。

public void createExecutor() {
        internalExecutor = true;
        TaskQueue taskqueue = new TaskQueue();
        TaskThreadFactory tf = new TaskThreadFactory(getName() + "-exec-", daemon, getThreadPriority());
        executor = new ThreadPoolExecutor(getMinSpareThreads(), getMaxThreads(), 60, TimeUnit.SECONDS,taskqueue, tf);
        taskqueue.setParent( (ThreadPoolExecutor) executor);
    }

从这里可以看到,这个创建连接的过程,就是通过网一个队列进行添加。这个getName()方法就是刚刚上面返回的http-nio-8080的那一部分。

这里可以看到构造一个TaskThreadFactory类。构造方法如下
 

public TaskThreadFactory(String namePrefix, boolean daemon, int priority) {
        SecurityManager s = System.getSecurityManager();
        group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
        this.namePrefix = namePrefix;
        this.daemon = daemon;
        this.threadPriority = priority;
    }

 重点看这个group,他是属于java.lang.ThreadGroup。构造方法中有这样一段代码
 

private ThreadGroup() {     // called from C code
        this.name = "system";
        this.maxPriority = Thread.MAX_PRIORITY;
        this.parent = null;
    }

Thread.MAX_PRIORITY=10;换言之,就是在通过Tomcat的形式建立连接的时候,新建的连接对象都会有用到ThreadGroup,在ThreadGroup中就有限制最大的数卫10.所以会出现http-nio-8080-exec-9的情况也很正常了。

相关文章

暂无评论

暂无评论...